应用技巧1:x&(x-1)【消除x(二进制)最后一位1】html
应用技巧2:<<左移【除2】java
应用技巧3:>>右移【×2】结合&1【判断最后一位是否为1】ios
def checkPowerof2(x): return x>0 and x&(x-1)==0
def isFour(n): m=1 while m<n: m=m<<2 return m==n
题目:数组
You are given an array A1,A2...AN. You have to tell how many pairs (i, j) exist such that 1 ≤ i < j ≤ N and Ai XOR Aj is odd.加密
思路:判断列表数据中最后一位是0的个数和1的个数,二者相乘即为结果。spa
代码:.net
T = int(input()) for i in range(T): N = int(input()) res = 0 arr = list(map(int,input().split())) odd , even = 0 , 0 for i in range(N): if arr[i]&1: odd += 1 else: even += 1 print(odd * even)
// Non Recursion class Solution { /** * @param S: A set of numbers. * @return: A list of lists. All valid subsets. */ public List<ArrayList<Integer>> subsets(int[] nums) { List<ArrayList<Integer>> result = new ArrayList<List<Integer>>(); int n = nums.length; Arrays.sort(nums); // 1 << n is 2^n // each subset equals to an binary integer between 0 .. 2^n - 1 // 0 -> 000 -> [] // 1 -> 001 -> [1] // 2 -> 010 -> [2] // .. // 7 -> 111 -> [1,2,3] for (int i = 0; i < (1 << n); i++) { List<Integer> subset = new ArrayList<Integer>(); for (int j = 0; j < n; j++) { // check whether the jth digit in i's binary representation is 1 if ((i & (1 << j)) != 0) { subset.add(nums[j]); } } result.add(subset); } return result; } }
java代码:3d
public class Solution { public int singleNumber(int[] nums) { int ones = 0, twos = 0; for(int i = 0; i < nums.length; i++){ ones = (ones ^ nums[i]) & ~twos; twos = (twos ^ nums[i]) & ~ones; } return ones; } }
public class Solution { public int[] singleNumber(int[] nums) { //用于记录,区分“两个”数组 int diff = 0; for(int i = 0; i < nums.length; i ++) { diff ^= nums[i]; } //取最后一位1 //先介绍一下原码,反码和补码 //原码,就是其二进制表示(注意,有一位符号位) //反码,正数的反码就是原码,负数的反码是符号位不变,其他位取反 //补码,正数的补码就是原码,负数的补码是反码+1 //在机器中都是采用补码形式存 //diff & (-diff)就是取diff的最后一位1的位置 diff &= -diff; int[] rets = {0, 0}; for(int i = 0; i < nums.length; i ++) { //分属两个“不一样”的数组 if ((nums[i] & diff) == 0) { rets[0] ^= nums[i]; } else { rets[1] ^= nums[i]; } } return rets; } }
c = a-b,sign(c),sign(a),sign(b):表示a,b,c的正负
sign(a) == sign(b):则不会溢出,sign(c)>0则返回a,不然返回b
sign(a) != sign(b):返回sign(a)、sign(b)大的一个。
给定两个32位整数a,b,可正,可负,可0,不能使用算术运算符,分别实现a和b的加减乘除运算。
两个运算【异或】以及【&加左移<<】。
不考虑进位:a^b
仅考虑进位:(a&b)<<1
将上面两个不断相加直到没有进位产生为最终结果。
代码:
def add(a,b): sum = a while b!=0: sum = a^b b = (a&b)<<1 a = sum return sum a = 19 b = 12 add(a,b)
#加法 def add(a,b): sum = a while b!=0: sum = a^b b = (a&b)<<1 a = sum return sum #减法 #取反加1得-b def negNum(b): return add(~b,1) #a+(-b) def minus(a,b): return add(a,negNum(b)) a = 19 b = 12 minus(a,b)
代码:
代码:
给定一个32位整数n,可为0,可为正,也可为负,返回该整数二进制表达中1的个数。
给定一个整型数组arr,其中只有一个数出现了奇数次,其余的数都出现了偶数次i,打印这个数。
进阶问题:有两个数出现了奇数次,其余的数都出现了偶数次,打印这两个数。
进阶思路:先将数组全部数字异或,最后结果就是两个出现一次的数字相互异或的结果,再将这两个数分别分在两个数组中进行异或。
http://www.javashuo.com/article/p-kltdyjse-do.html
给定一个整型数组arr和一个大于1的整数k。已知arr中只有1个数出现了1次,其余的数都出现了k次,请返回只出现了1次的数。
定律:k个相同的k进制无进位相加的结果为0.
例如: 两个相同的2进制 100110101
100110101
无进位相加 结果 0000000
解法:把数组中的每一个元素当作k进制 , 全部元素相加后获得的k进制结果就是 那个只出现一次的数,而后转成相应的十进制,得解。
详细解释:
一个重要结论:
解该题:
def onceNum(arr,k): eO = [0] * 32 for i in range(len(arr)): setExclusiveOr(eO,arr[i],k) res = getNumFromKSysNum(eO,k) return res #得到全部的K进制无进位加和 def setExclusiveOr(eO,value,k): curKSysNum = getKSysNumFromNum(value,k) for i in range(len(eO)): eO[i] = (eO[i] + curKSysNum[i]) % k #得到K进制,res返回的是k进制 def getKSysNumFromNum(value,k): res = [0] * 32 index = 0 while value != 0: res[index] = value % k index += 1 value = value // k return res
#将结果的那个K进制数转成十进制数输出
def getNumFromKSysNum(eO,k): res = 0 for i in range(len(eO) - 1,-1,-1): res = res * k + eO[i] return res arr = [1,1,1,2,2,2,4] k = 3 onceNum(arr,k)
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
写出指数的二进制表达,例如13表达为二进制1101。
经过&1和>>1来逐位读取1101,为1时将该位表明的乘数累乘到最终结果。
举例:10^1101 = 10^0001*10^0100*10^1000
def Power(self, base, exponent): # write code here #return math.pow(base,exponent) if base == 0 : return 0 if exponent == 0: return 1 elif exponent < 0: n = -exponent else: n = exponent res = 1 cur = base while n: if (n&1) == 1: res *= cur cur *= cur n = n >> 1 return res if exponent > 0 else (1/res)
【1 ,1,2,3,3】--->【1,1,10,11,11】---> sum(1,1,10,11,11) --->1010【两个1,答案为2】
题目描述:小Q十分富有,拥有很是多的硬币,小Q拥有的硬币是有规律的,对于全部的非负整数K,小Q刚好各有两个面值为2^k的硬币,全部小Q拥有的硬币就是1,1,2,2,4,4,8,8.....小Q有一天去商店购买东西须要支付n元钱,小Q想知道有多少种方案从他拥有的硬币中选取一些拼凑起来刚好是n元(若是两种方案某个面值的硬币选取的个数不同就考虑为不同的方案)
输入:
输入包括一个整数n(1<=n<=10^18),表示小Q须要支付多少钱,注意n的范围
输出:
输出一个整数,表示小Q能够拼凑出n元钱的方案数
样例输入:6
样例输出:3 (例如4+2, 4+1+1, 2+2+1+1)
一个很秒的思路:https://blog.csdn.net/xiaoquantouer/article/details/78076764
将硬币分为两份:1,2,4,8,16,... 和1,2,4,8,16,...
组成两个数值为a, b的两个数,他们的和是a+b=n;
a在第一份中只有可能有一种组合方式(采用二进制的思想,任何一个数均可以由若干个2^i的数相加的和组成),而b = n-a也只会有一种组合形式。
将a和b使用二进制表示,举个例子n=11,有a=101, b=110这种组合,即a = 1+0+4=5,b=0+2+4=6。可是注意到会有重复的状况,好比111+100和101+110本质上是同一种组合方法,因此须要将二个数作二进制异或而后去重。
代码:
#include <iostream> #include<set> using namespace std; int main() { int n; while(cin>>n){ set<int> countset; for(int i=1;i<=n/2;i++){ int result =i^(n-i); countset.insert(result); } cout<<countset.size()<<endl; } return 0; }