位运算题单
基础题
img
1486.
数组异或操作
直接模拟()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Solution { public : int xorOperation (int n, int start) { int ans = 0 ; for (int i = 0 ; i < n; ++i) { ans ^= (start + i * 2 ); } return ans; } };
2595.
奇偶位数
水题啊
1 2 3 4 5 6 7 8 9 10 class Solution {public : vector<int > evenOddBit (int n) { vector<int > ans (2 ) ; for (int i = 0 ; n != 0 ; i ^= 1 , n >>= 1 ) ans[i] += n & 1 ; return ans; } };
231. 2
的幂
小技巧
1 2 3 4 5 6 7 8 class Solution { public : bool isPowerOfTwo (int n) { return n > 0 && (n & (n - 1 )) == 0 ; } };
342.
4的幂
可以通过 n 除以 3 的余数是否为 1 来判断 n 是否是 4 的幂。
1 2 3 4 5 6 7 8 class Solution {public : bool isPowerOfFour (int n) { return n > 0 && (n & (n - 1 )) == 0 && n % 3 == 1 ; } };
476.
数字的补数
位运算大法好
1 2 3 4 5 6 7 8 9 10 11 12 class Solution { public int findComplement (int num) { int res = 1 ; while (res < num) { res = res << 1 ; res++; } return num ^ res; } }
191.
位1的个数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Solution { public : int hammingWeight (uint32_t n) { int ret = 0 ; for (int i = 0 ; i < 32 ; i++) { if (n & (1 << i)) { ret++; } } return ret; } };
338.
比特位计数
显然扫一遍每次log,就是nlogn,但这显然不是正解
考虑dp,转移的话由他的前面一位转移过来
nlogn
n & n-1 的值是
去掉二进制n最右边1的值 ;
比如 1010 & 1001 =
1000;用这个可以非常优雅的计算一个数里面的1的个数!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution {public : int countOnes (int x) { int ones = 0 ; while (x > 0 ) { x &= (x - 1 ); ones++; } return ones; } vector<int > countBits (int n) { vector<int > bits (n + 1 ) ; for (int i = 0 ; i <= n; i++) { bits[i] = countOnes (i); } return bits; } };
n
1 2 3 4 5 6 7 8 9 10 11 12 13 class Solution { public : vector<int > countBits (int n) { vector<int > res (n+1 ) ; for (int i = 1 ; i <= n; ++i) { res[i] = res[i >> 1 ] + (i & 1 ); } return res; } };
1356.
根据数字二进制下 1 的数目排序
只要你会了上一题的O(n)做法,本题简直是探囊取物
本题题解写的有些冗余,改了一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution { public : vector<int > sortByBits (vector<int >& arr) { vector<int > bit (10001 , 0 ) ; for (int i = 1 ; i <= 10000 ; ++i) { bit[i] = bit[i >> 1 ] + (i & 1 ); } sort (arr.begin (), arr.end (), [&](int x, int y) { if (bit[x] == bit[y]) { return x < y; } return (bit[x] < bit[y]) ; }); return arr; } };
461.
汉明距离
由于上述结论,异或求1即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution { public : int hammingDistance (int x, int y) { int ret = x^y; int ans = 0 ; while (ret) { ret&=(ret-1 ); ans++; } return ans; } };
2220.
转换数字的最少位翻转次数
与上面一道题一致
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution { public : int minBitFlips (int start, int goal) { int res = 0 ; int tmp = start ^ goal; while (tmp) { res += tmp & 1 ; tmp >>= 1 ; } return res; } };
868.
二进制间距
一眼题了,只需要记录上一个即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Solution { public : int binaryGap (int n) { int last = -1 , ans = 0 ; for (int i = 0 ; n; ++i) { if (n & 1 ) { if (last != -1 ) { ans = max (ans, i - last); } last = i; } n >>= 1 ; } return ans; } };
2917.
找出数组中的 K-or 值
模拟一下基本的判1操作即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { public : int findKOr (vector<int >& a, int k) { int n=a.size (),ans=0 ,x; vector<int > s (35 ) ; for (int i=0 ;i<n;i++) { x=a[i]; for (int j=0 ;j<31 ;j++) if (x&(1 <<j)) s[j]++; } for (int j=0 ;j<31 ;j++) if (s[j]>=k) ans+=(1 <<j); return ans; } };
今天的最后一题:
693.
交替位二进制数
直接模拟即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { public : bool hasAlternatingBits (int n) { int prev = 2 ; while (n != 0 ) { int cur = n % 2 ; if (cur == prev) { return false ; } prev = cur; n /= 2 ; } return true ; } };
位运算力扣基础题单中阶
2980.
检查按位或是否存在尾随零
判断两个偶数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution {public : bool hasTrailingZeros (vector<int >& nums) { int num = 0 ; for (auto i : nums){ if (i % 2 == 0 ){ num++; if (num >= 2 ){ return true ; } } } return false ; } };
1318.
或运算的最小翻转次数
很水的题目,分类讨论一下即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution {public : int minFlips (int a, int b, int c) { int ans = 0 ; for (int i = 0 ; i < 31 ; ++i) { int bit_a = (a >> i) & 1 ; int bit_b = (b >> i) & 1 ; int bit_c = (c >> i) & 1 ; if (bit_c == 0 ) { ans += bit_a + bit_b; } else { ans += (bit_a + bit_b == 0 ); } } return ans; } };
2419.
按位与最大的最长子数组
思路太直接了,找到最大值,算最大子个数,用个最长连续就写完了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution { public : int longestSubarray (vector<int >& nums) { int n = nums.size (); int mx = 0 ; for (int x : nums) mx = max (mx, x); int ans = 1 , cnt = 0 ; for (int x : nums) { if (x == mx) cnt++; else ans = max (ans, cnt), cnt = 0 ; } ans = max (ans, cnt); return ans; } };
2871.
将数组分割成最多数目的子数组
也是脑经急转弯的题目,其实也是不难的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution {public : int maxSubarrays (vector<int >& nums) { int mask = nums[0 ]; for (int x : nums) mask &= x; if (mask != 0 ) return 1 ; int cnt = 0 ; int cur = nums[0 ]; for (int i = 0 ; i < nums.size ();) { cur &= nums[i]; if (cur == mask) { cnt++; if (i == nums.size () - 1 ) break ; else cur = nums[i + 1 ]; } i++; } return cnt; } };
2401.
最长优雅子数组
此题比较有难度,需要结合滑动窗口,也就是双指针的思想,具体一个数进来需要或起来,因为如果不或是没办法知道这个位有没有数字出现过的,至于怎么样左滑移出去,这个操作就是异或了,由于已经保证了数字之前的位数的不重复性,因此只需要异或就可以达到一个弹出的作用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution { public : int longestNiceSubarray (vector<int >& nums) { int n = nums.size (); int i = 0 ; if (n == 1 ) return 1 ; int j = i + 1 ; int ans = 1 ; long long now = nums[i]; while (i < n && j < n) { while ((i < j) && ((now & nums[j]) != 0 )) { now ^= nums[i]; ++i; } now |= nums[j]; ans = max (ans, j - i + 1 ); ++j; } return ans; } };
3097.
或值至少为 K 的最短子数组 II
也是滑动窗口不过是哈希加上滑动窗口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class Solution { public : int minimumSubarrayLength (vector<int >& nums, int k) { if (k == 0 ) return 1 ; int ans = INT32_MAX, n = nums.size (), cur = 0 ; vector<int > mem (32 ) ; int l = 0 , r = 0 ; while (l <= r && r < n) { for (int j = 0 ; j < 32 ; ++j){ if ((nums[r] >> j) & 1 ) { ++mem[j]; if (((cur >> j) & 1 ) == 0 ) cur += (1 << j); } } ++r; while ((cur >= k || r == n) && l < r) { if (cur >= k) ans = min (ans, r - l); for (int j = 0 ; j < 32 ; ++j) { if ((nums[l] >> j) & 1 ) { --mem[j]; if (mem[j] == 0 ) cur -= (1 << j); } } ++l; } } return ans == INT32_MAX ? -1 : ans; } };
3133.
数组最后一个元素的最小值
从低到高开始填充数字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 using ll=long long ;class Solution { public :long long minEnd (int n, int x) { int i,j; ll res=x; n--; for (i=0 ,j=0 ;i<=30 ;i++,j++) { while ((res>>j)&1 ) j++; if (!((n>>i)&1 )) continue ; res|=(1LL <<j); } return res; } };
2680.
最大或值
找最高位的1去异或,而且只选择一个数字,因此只需要处理一下后缀和,前缀和直接计算进行预处理即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { public : long long maximumOr (vector<int > &nums, int k) { int n = nums.size (), suf[n + 1 ]; suf[n] = 0 ; for (int i = n - 1 ; i; i--) suf[i] = suf[i + 1 ] | nums[i]; long long ans = 0 ; for (int i = 0 , pre = 0 ; i < n; i++) { ans = max (ans, pre | ((long long ) nums[i] << k) | suf[i + 1 ]); pre |= nums[i]; } return ans; } };
2411.
按位或最大的最小子数组长度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Solution { public int [] smallestSubarrays (int [] nums) { int n = nums.length; int [] dp = new int [32 ]; Arrays.fill (dp, -1 ); int [] ans = new int [n]; for (int i = n-1 ; i >= 0 ; i--) { int max = 1 ; for (int j = 0 ; j < 32 ; j++) { if (((nums[i] >> j) & 1 ) == 1 ) { dp[j] = i; } if (dp[j] != -1 ) { max = Math.max (max, dp[j]-i+1 ); } } ans[i] = max; } return ans; } }