leetcode - 位运算题目汇总(上)
最近在看位运算的知识,十分感叹于位运算的博大精深,正好leetcode有 Bit Manipulation 的专题,正好拿来练练手。
Subsets
给出一个由不同的数字组成的数组,枚举它的子数组(子集)。
这道题我之前用递归解过,而且效率还不错(beat 83.33%),解法如下不加详述了:
/** * @param {number[]} nums * @return {number[][]} */var ans, res, len;function dfs(index, nums) { ans.push(res.concat()); for (var i = index; i < len; i++) { res.push(nums[i]); dfs(i + 1, nums); res.pop(); }}var subsets = function(nums) { nums.sort(function(a, b) { return a - b; }); ans = [], res = [], len = nums.length; dfs(0, nums); return ans;};
如果用位运算解,这是一道经典的枚举子集。
比如我们有数组[1, 2, 3]
,还是要用到标志位的概念,全集为1 1 1
,全集表示都取,它的子集有1 0 1
、 1 1 0
、 1 0 0
等等,我们通过枚举子集,然后再通过子集获取原来数组的元素即可。
比如子集 1 0 1
,我们可以依次获取最右边的1,然后根据获取的1的大小判断数组元素的index位置从而获取数组,之后把该1置为0即可。
/*** @param {number[]} nums* @return {number[][]}*/var subsets = function(nums) { nums.sort(function(a, b) { return a - b; }); var all = (1 << nums.length) - 1 , ans = []; // 枚举子集 for (i = all; i; i = (i - 1) & all) { var tmp = i , res = []; while (tmp) { var rightMostOne = tmp & (-tmp) , index = Math.log(rightMostOne) / Math.log(2); res.push(nums[index]); tmp = tmp & (tmp - 1); } ans.push(res); } // 子集的枚举没有0,所以要special insert ans.push([]); return ans;};
Power of Two
判断一个数是不是2的幂。如果一个数是2的幂,那么该数与上该数-1为0。我们以8举例:
1 0 0 00 1 1 1
很明显,上面两数做与运算的结果是0。但是有个特殊的情况是,0 & (0 - 1) === 0
,所以我们还得判断该数为正。
/** * @param {number} n * @return {boolean} */var isPowerOfTwo = function(n) { return (!(n & (n - 1)) && n > 0);};
这里加强下,如果知道某数是2的幂,求解这个指数值。即Math.pow(2, x) = n
,求x的值。
也很简单,用个log的换底公式(其实没有涉及位运算):
return Math.log(n) / Math.IN2;
Missing Number
给出一个0~n组成的数组[0, 1, 2, 3 ... n]
,从中随即去掉一个数字,给你新的数组,求解被去掉的数字。比如给你[0, 1, 3]
,返回2
。
这题涉及^
运算的性质:
// if a ^ b = c;// thena ^ c = b;b ^ c = a;
解法也就呼之欲出了。还是假设数组[0, 1, 3]
,我们可以知道n为3(等于数组长度),从而可以计算出0 ^ 1 ^ 2 ^ 3
的值,我们把它赋值给c;然后我们计算所给数组的元素的异或值,赋值给a,假设被舍弃的元素为b,我们可以得到如下等式:
a ^ b = c;
根据前边所讲:
b = a ^ c;
完整代码:
/** * @param {number} n * @return {boolean} *//** * @param {number[]} nums * @return {number} */var missingNumber = function(nums) { var a = nums.reduce(function(pre, item) { return pre ^ item; }); var b = nums.reduce(function(pre, item, index) { return pre ^ index; }, nums.length); return a ^ b;};