目录:
技巧:
应用技巧1:x&(x-1)【消除x(二进制)最后一位1】
-
-
-
- 判断是否为2的幂
-
-
应用技巧2:<<左移【除2】
-
-
-
- 判断是否为2的幂
- 判断是否为4的幂
-
-
应用技巧3:>>右移【×2】结合&1【判断最后一位是否为1】
题目:
技巧:
1、应用技巧1:与&【消除x(二进制)最后一位1】
def checkPowerof2(x): return x>0 and x&(x-1)==0
应用技巧二:判断n是否为4的幂:
def isFour(n): m=1 while m<n: m=m<<2 return m==n
3、应用技巧3:>>右移【×2】结合&1
题目:
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 AiXOR Aj is odd.
思路:判断列表数据中最后一位是0的个数和1的个数,两者相乘即为结果。
代码:
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)
4、应用技巧4:子集
// 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; } }
5、应用技巧5:异或
java代码:
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; } }
题目:
1、如何不用额外空间交换两个变量:
2、不用任何比较判断找出两个数中较大的数
法一:得到a-b的值的符号,若a-b是负数,则返回b,否则a。【存在溢出风险,a、b正负不同时,相减会溢出】
法二:
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)大的一个。
3、只用位运算不用算术运算实现整数的加减乘除运算
给定两个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)
减法思路:a-b 实现a+(-b)即可。b取反加1(补码)即为-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)
乘法运算:
代码:
除法思路:
代码:
4、整数的二进制表达中有多少个1
给定一个32位整数n,可为0,可为正,也可为负,返回该整数二进制表达中1的个数。
简单思路:右移判断1的个数(循环32次)
循环次数更少的思路:1的个数次数
法3:循环次数和法2一样:
法四:平行算法:
5、在其他数都出现偶数次的数组中找到出现奇数次的数
给定一个整型数组arr,其中只有一个数出现了奇数次,其他的数都出现了偶数次i,打印这个数。
进阶问题:有两个数出现了奇数次,其他的数都出现了偶数次,打印这两个数。
进阶思路:先将数组所有数字异或,最后结果就是两个出现一次的数字相互异或的结果,再将这两个数分别分在两个数组中进行异或。
https://www.cnblogs.com/Lee-yl/p/9123793.html
6、在其他数都出现K次的数组中找到只出现一次的数
给定一个整型数组arr和一个大于1的整数k。已知arr中只有1个数出现了1次,其他的数都出现了k次,请返回只出现了1次的数。
思路:时间O(N),空间O(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)
7、请设置一种加密过程,完成对明文text的加密和解密工作。
8、数的幂
给定一个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)