1 介绍
本博客用来记录灵神力扣题单之位运算
2 训练
2.1 基础题
题目1:2595. 奇偶位数
解题思路:模拟。
C++代码如下,
class Solution {
public:
vector<int> evenOddBit(int n) {
int even = 0, odd = 0;
for (int i = 0; i < 32; ++i) {
if ((n >> i) & 1) {
if (i & 1) odd += 1;
else even += 1;
}
}
return {even, odd};
}
};
python3代码如下,
class Solution:
def evenOddBit(self, n: int) -> List[int]:
even, odd = 0, 0
for i in range(32):
if (n >> i) & 1:
if i & 1:
odd += 1
else:
even += 1
return [even, odd]
题目2:231. 2 的幂
解题思路:直接模拟。
C++代码如下,
class Solution {
public:
bool isPowerOfTwo(int n) {
if (n < 1) return false;
int cnt = 0;
for (int i = 0; i < 31; ++i) {
if ((n >> i) & 1) cnt += 1;
}
return cnt == 1;
}
};
python3代码如下,
class Solution:
def isPowerOfTwo(self, n: int) -> bool:
if n < 1:
return False
cnt = 0
for i in range(32):
if (n >> i) & 1:
cnt += 1
return cnt == 1
题目3:342. 4的幂
解题思路:模拟。
C++代码如下,
class Solution {
public:
bool isPowerOfFour(int n) {
if (n < 1) return false;
vector<int> nums;
for (int i = 0; i < 31; ++i) {
if ((n >> i) & 1) {
nums.emplace_back(i);
}
}
if (nums.size() == 1 && nums[0] % 2 == 0) return true;
else return false;
}
};
python3代码如下,
class Solution:
def isPowerOfFour(self, n: int) -> bool:
if n < 1:
return False
nums = []
for i in range(32):
if (n >> i) & 1:
nums.append(i)
if len(nums) == 1 and nums[0] % 2 == 0:
return True
else:
return False
题目4:476. 数字的补数
解题思路为:模拟。
C++代码如下,
class Solution {
public:
int findComplement(int num) {
int res = 0;
for (int i = 0; i < 31; ++i) {
if (num < (1 << i)) break;
if ((num >> i) & 1) {
//pass
} else {
res += 1 << i;
}
}
return res;
}
};
python3代码如下,
class Solution:
def findComplement(self, num: int) -> int:
res = 0
for i in range(32):
if num < (1 << i):
break
x = (num >> i) & 1
if x == 1:
pass
else:
res += 1 << i
return res
题目5:191. 位1的个数
解题思路:模拟。
C++代码如下,
class Solution {
public:
int hammingWeight(int n) {
int res = 0;
for (int i = 0; i < 31; ++i) {
if ((n >> i) & 1) {
res += 1;
}
}
return res;
}
};
python3代码如下,
class Solution:
def hammingWeight(self, n: int) -> int:
res = 0
for i in range(32):
if (n >> i) & 1:
res += 1
return res
题目6:338. 比特位计数
解题思路:模拟。
C++代码如下,
class Solution {
public:
vector<int> countBits(int n) {
vector<int> res;
for (int x = 0; x < n+1; ++x) {
int ans = 0;
for (int i = 0; i < 32; ++i) {
if ((x >> i) & 1) {
ans += 1;
}
}
res.emplace_back(ans);
}
return res;
}
};
python3代码如下,
class Solution:
def countBits(self, n: int) -> List[int]:
res = []
for x in range(n+1):
ans = 0
for i in range(32):
if (x >> i) & 1:
ans += 1
res.append(ans)
return res
解题思路:模拟。
C++代码如下,
class Solution {
public:
int minChanges(int n, int k) {
int res = 0;
for (int i = 0; i < 31; ++i) {
int x = (n >> i) & 1;
int y = (k >> i) & 1;
if (x != y) {
if (x == 1) res += 1;
else return -1;
}
}
return res;
}
};
python3代码如下,
class Solution:
def minChanges(self, n: int, k: int) -> int:
res = 0
for i in range(32):
x = (n >> i) & 1
y = (k >> i) & 1
if x != y:
if x == 1:
res += 1
else:
return -1
return res
解题思路:模拟。
C++代码如下,
class Solution {
public:
vector<int> sortByBits(vector<int>& arr) {
sort(arr.begin(), arr.end(), [&](const int x, const int y) {
int cnt1 = 0, cnt2 = 0;
for (int i = 0; i < 31; ++i) {
if ((x >> i) & 1) cnt1 += 1;
if ((y >> i) & 1) cnt2 += 1;
}
return cnt1 < cnt2 || (cnt1 == cnt2 && x < y);
});
return arr;
}
};
python3代码如下,
class Solution:
def sortByBits(self, arr: List[int]) -> List[int]:
arr.sort(key=lambda x : (bin(x).count('1'),x))
return arr
题目9:461. 汉明距离
解题思路:模拟。
C++代码如下,
class Solution {
public:
int hammingDistance(int x, int y) {
x = x ^ y;
int res = 0;
for (int i = 0; i < 31; ++i) {
if ((x >> i) & 1) res += 1;
}
return res;
}
};
python3代码如下,
class Solution:
def hammingDistance(self, x: int, y: int) -> int:
x = x ^ y
res = 0
for i in range(32):
if (x >> i) & 1:
res += 1
return res
题目10:2220. 转换数字的最少位翻转次数
解题思路:模拟。
C++代码如下,
class Solution {
public:
int minBitFlips(int start, int goal) {
int x = start ^ goal;
int res = 0;
for (int i = 0; i < 31; ++i) {
if ((x >> i) & 1) res += 1;
}
return res;
}
};
python3代码如下,
class Solution:
def minBitFlips(self, start: int, goal: int) -> int:
x = start ^ goal
res = 0
for i in range(32):
if (x >> i) & 1:
res += 1
return res
题目11:868. 二进制间距
解题思路:模拟。
C++代码如下,
class Solution {
public:
int binaryGap(int n) {
vector<int> nums;
int res = 0;
for (int i = 0; i < 31; ++i) {
if ((n >> i) & 1) nums.emplace_back(i);
}
if (nums.size() < 2) return 0;
for (int i = 0; i < nums.size()-1; ++i) {
res = max(res, nums[i+1]-nums[i]);
}
return res;
}
};
python3代码如下,
class Solution:
def binaryGap(self, n: int) -> int:
res = 0
indices = []
for i in range(32):
if (n >> i) & 1:
indices.append(i)
if len(indices) < 2:
return 0
for i in range(len(indices)-1):
res = max(res, indices[i+1]-indices[i])
return res
题目12:3211. 生成不含相邻零的二进制字符串
解题思路:dfs。
C++代码如下,
class Solution {
public:
vector<string> validStrings(int n) {
vector<string> res;
function<void(int,string)> dfs =[&] (int i, string cur) -> void {
if (i == n) {
res.emplace_back(cur);
return;
}
if (i == 0 || cur.back() == '1') {
cur += '0';
dfs(i+1,cur);
cur.pop_back();
}
cur += '1';
dfs(i+1,cur);
cur.pop_back();
};
string cur = "";
dfs(0, cur);
return res;
}
};
python3代码如下,
class Solution:
def validStrings(self, n: int) -> List[str]:
res = []
def dfs(i: int, cur: list) -> None:
if i == n:
res.append("".join(cur))
return
if cur == [] or cur[-1] == '1':
cur.append('0')
dfs(i+1,cur)
cur.pop()
cur.append('1')
dfs(i+1,cur)
cur.pop()
dfs(0,[])
return res
题目13:2917. 找出数组中的 K-or 值
解题思路:模拟。
C++代码如下,
class Solution {
public:
int findKOr(vector<int>& nums, int k) {
vector<int> cnt(31, 0);
for (int i = 0; i < 31; ++i) {
for (int num : nums) {
if ((num >> i) & 1) {
cnt[i] += 1;
}
}
}
int res = 0;
for (int i = 0; i < 31; ++i) {
if (cnt[i] >= k) res += 1 << i;
}
return res;
}
};
python3代码如下,
class Solution:
def findKOr(self, nums: List[int], k: int) -> int:
cnt = [0] * 32
for i in range(32):
for num in nums:
if (num >> i) & 1:
cnt[i] += 1
res = 0
for i in range(32):
if cnt[i] >= k:
res += 1 << i
return res
题目14:693. 交替位二进制数
解题思路:模拟。
C++代码如下,
class Solution {
public:
bool hasAlternatingBits(int n) {
for (int i = 0; i < 30; ++i) {
if ((1 << i) > n) break;
int x = (n >> i) & 1;
int y = (n >> (i+1)) & 1;
if (x == y) return false;
}
return true;
}
};
python3代码如下,
class Solution:
def hasAlternatingBits(self, n: int) -> bool:
for i in range(31):
if (1 << i) > n:
break
x = (n >> i) & 1
y = (n >> (i+1)) & 1
if x == y:
return False
return True
题目15:2657. 找到两个数组的前缀公共数组
解题思路:模拟。
C++代码如下,
class Solution {
public:
vector<int> findThePrefixCommonArray(vector<int>& A, vector<int>& B) {
int n = A.size();
vector<int> res(n, 0);
set<int> a, b;
for (int i = 0; i < n; ++i) {
a.insert(A[i]);
b.insert(B[i]);
int cnt = 0;
for (auto x : a) {
if (b.find(x) != b.end()) cnt += 1;
}
res[i] = cnt;
}
return res;
}
};
python3代码如下,
class Solution:
def findThePrefixCommonArray(self, A: List[int], B: List[int]) -> List[int]:
n = len(A)
res = [0] * n
a = set()
b = set()
for i in range(n):
a.add(A[i])
b.add(B[i])
c = a & b
res[i] = len(c)
return res
2.2 异或(XOR)的性质
题目16:1486. 数组异或操作
解题思路:模拟即可。
C++代码如下,
class Solution {
public:
int xorOperation(int n, int start) {
int res = 0;
for (int i = 0; i < n; ++i) {
int x = start + 2 * i;
res ^= x;
}
return res;
}
};
python3代码如下,
class Solution:
def xorOperation(self, n: int, start: int) -> int:
res = 0
for i in range(n):
x = start + 2 * i
res ^= x
return res
题目17:1720. 解码异或后的数组
解题思路:模拟即可。
C++代码如下,
class Solution {
public:
vector<int> decode(vector<int>& encoded, int first) {
vector<int> res = {first};
for (auto x : encoded) {
int y = res.back() ^ x;
res.emplace_back(y);
}
return res;
}
};
python3代码如下,
class Solution:
def decode(self, encoded: List[int], first: int) -> List[int]:
res = [first]
for x in encoded:
y = res[-1] ^ x
res.append(y)
return res
题目18:2433. 找出前缀异或的原始数组
解题思路:模拟即可。
C++代码如下,
class Solution {
public:
vector<int> findArray(vector<int>& pref) {
vector<int> res = {pref[0]};
for (int i = 1; i < pref.size(); ++i) {
int x = pref[i-1] ^ pref[i];
res.emplace_back(x);
}
return res;
}
};
python3代码如下,
class Solution:
def findArray(self, pref: List[int]) -> List[int]:
res = [pref[0]]
for i in range(1,len(pref)):
x = pref[i-1] ^ pref[i]
res.append(x)
return res
题目19:1310. 子数组异或查询
解题思路:前缀和。
C++代码如下,
class Solution {
public:
vector<int> xorQueries(vector<int>& arr, vector<vector<int>>& queries) {
int n = arr.size();
vector<int> s(n+1, 0);
for (int i = 1; i < n+1; ++i) {
s[i] = s[i-1] ^ arr[i-1];
}
vector<int> res;
for (auto query : queries) {
int left = query[0];
int right = query[1];
int x = s[right+1] ^ s[left];
res.emplace_back(x);
}
return res;
}
};
python3代码如下,
#方法2
class Solution:
def xorQueries(self, arr: List[int], queries: List[List[int]]) -> List[int]:
n = len(arr)
s = [0] * (n+1)
for i in range(1,n+1):
s[i] = s[i-1] ^ arr[i-1]
res = []
for left,right in queries:
x = s[right+1] ^ s[left]
res.append(x)
return res
#方法1
class Solution:
def xorQueries(self, arr: List[int], queries: List[List[int]]) -> List[int]:
n = len(arr)
cnt = [[0] * 32 for _ in range(n+1)] #[i,j]中第0位为1的个数,cnt[j+1][0]-cnt[i][0]
for i in range(1,n+1):
x = arr[i-1]
for j in range(32):
if (x >> j) & 1:
cnt[i][j] += cnt[i-1][j] + 1
else:
cnt[i][j] += cnt[i-1][j]
res = []
for left,right in queries:
t = 0
for i in range(32):
a = cnt[right+1][i] - cnt[left][i]
if a > 0 and a % 2 == 1:
t += 1 << i
res.append(t)
return res
题目20:2683. 相邻值的按位异或
解题思路:模拟即可。
C++代码如下,
class Solution {
public:
bool doesValidArrayExist(vector<int>& derived) {
int res = 0;
for (auto x : derived) res ^= x;
return res == 0;
}
};
python3代码如下,
class Solution:
def doesValidArrayExist(self, derived: List[int]) -> bool:
res = 0
for x in derived:
res ^= x
return res == 0
题目21:1829. 每个查询的最大异或值
解题思路:模拟。
C++代码如下,
class Solution {
public:
vector<int> getMaximumXor(vector<int>& nums, int maximumBit) {
int n = nums.size();
vector<int> s(n+1, 0);
for (int i = 1; i < n+1; ++i) {
s[i] = s[i-1] ^ nums[i-1];
}
//[left,right]的异或和为s[right+1]^s[left]
vector<int> res(n, 0);
for (int i = 0; i < n; ++i) {
int x = s[n-i] ^ s[0];
int y = 0;
for (int j = 0; j < 31; ++j) {
if (j == maximumBit) break;
if ((x >> j) & 1) {
//pass
} else {
y += 1 << j;
}
}
res[i] = y;
}
return res;
}
};
python3代码如下,
class Solution:
def getMaximumXor(self, nums: List[int], maximumBit: int) -> List[int]:
n = len(nums)
s = [0] * (n+1)
for i in range(1,n+1):
s[i] = s[i-1] ^ nums[i-1]
#[left,right]的异或和为s[right+1]^s[left]
res = [0] * n
for i in range(n):
#[0,n-1-i]的异或和
x = s[n-i] ^ s[0]
y = 0 #要使得结果最大
for j in range(32):
if j == maximumBit:
break
if (x >> j) & 1:
pass
else:
y += 1 << j
#ans = x ^ y
res[i] = y
return res
解题思路:模拟。
C++代码如下,
class Solution {
public:
int minOperations(vector<int>& nums, int k) {
int x = 0;
for (auto num : nums) x ^= num;
x ^= k;
int res = 0;
for (int i = 0; i < 31; ++i) {
if ((x >> i) & 1) {
res += 1;
}
}
return res;
}
};
python3代码如下,
class Solution:
def minOperations(self, nums: List[int], k: int) -> int:
x = 0
for num in nums:
x ^= num
x = x ^ k
res = 0
for i in range(32):
if (x >> i) & 1:
res += 1
return res
解题思路:模拟。
C++代码如下,
class Solution {
public:
int countTriplets(vector<int>& arr) {
int n = arr.size();
vector<int> s(n+1,0);
for (int i = 1; i < n+1; ++i) {
s[i] = s[i-1] ^ arr[i-1];
}
int cnt = 0;
for (int i = 0; i < n; ++i) {
for (int j = i+1; j < n; ++j) {
//[i,j-1]的异或和
int x = s[j] ^ s[i];
for (int k = j; k < n; ++k) {
//[j,k]的异或和
int y = s[k+1] ^ s[j];
if (x == y) cnt += 1;
}
}
}
return cnt;
}
};
python3代码如下,
class Solution:
def countTriplets(self, arr: List[int]) -> int:
n = len(arr)
s = [0] * (n+1)
for i in range(1,n+1):
s[i] = s[i-1] ^ arr[i-1]
res = 0
for i in range(n):
for j in range(i+1,n):
#[i,j-1]的异或和
x = s[j] ^ s[i]
for k in range(j,n):
#[j,k]的异或和
y = s[k+1] ^ s[j]
if x == y:
res += 1
return res
题目24:2429. 最小异或
解题思路:模拟。
C++代码如下,
class Solution {
public:
int get_1_cnt(int x) {
int res = 0;
for (int i = 0; i < 31; ++i) {
if ((x >> i) & 1) res += 1;
}
return res;
}
int minimizeXor(int num1, int num2) {
int n1 = get_1_cnt(num1);
int n2 = get_1_cnt(num2);
if (n1 == n2) {
return num1;
} else if (n1 > n2) {
int res = num1;
//1多了
int cnt = n1 - n2;
for (int i = 0; i < 31; ++i) {
if ((res >> i) & 1) {
res -= 1 << i;
cnt -= 1;
if (cnt == 0) break;
}
}
return res;
} else {
int res = num1;
//1少了
int cnt = n2 - n1;
for (int i = 0; i < 31; ++i) {
if ((res >> i) & 1) {
//pass
} else {
res += 1 << i;
cnt -= 1;
if (cnt == 0) break;
}
}
return res;
}
}
};
python3代码如下,
class Solution:
def minimizeXor(self, num1: int, num2: int) -> int:
def get_1_cnt(x: int) -> int:
res = 0
for i in range(32):
if (x >> i) & 1:
res += 1
return res
n1 = get_1_cnt(num1)
n2 = get_1_cnt(num2)
if n1 == n2:
return num1
elif n1 > n2:
cnt = n1 - n2
res = num1
#多了1
for i in range(32):
if (res >> i) & 1:
res -= 1 << i
cnt -= 1
if cnt == 0:
break
return res
else:
cnt = n2 - n1
res = num1
#少了1
for i in range(32):
if (res >> i) & 1:
pass
else:
res += 1 << i
cnt -= 1
if cnt == 0:
break
return res
题目25:2527. 查询数组异或美丽值
解题思路:所有元素的异或和。
C++代码如下,
class Solution {
public:
int xorBeauty(vector<int>& nums) {
int res = 0;
for (auto num : nums) res ^= num;
return res;
}
};
python3代码如下,
class Solution:
def xorBeauty(self, nums: List[int]) -> int:
res = 0
for num in nums:
res ^= num
return res
题目26:2317. 操作后的最大异或和
解题思路:模拟即可。
C++代码如下,
class Solution {
public:
int maximumXOR(vector<int>& nums) {
int cnt[32] = {0};
for (auto num : nums) {
for (int i = 0; i < 31; ++i) {
if ((num >> i) & 1) cnt[i] += 1;
}
}
int res = 0;
for (int i = 0; i < 31; ++i) {
if (cnt[i] > 0) res += 1 << i;
}
return res;
}
};
python3代码如下,
class Solution:
def maximumXOR(self, nums: List[int]) -> int:
cnt = [0] * 32
for num in nums:
for i in range(32):
if (num >> i) & 1:
cnt[i] += 1
res = 0
for i in range(32):
if cnt[i] > 0:
res += 1 << i
return res
题目27:2588. 统计美丽子数组数目
解题思路:前缀异或和,哈希表。
C++代码如下,
class Solution {
public:
long long beautifulSubarrays(vector<int>& nums) {
long long res = 0;
unordered_map<int,long long> cnt;
int cur = 0;
cnt[0] = 1;
for (auto num : nums) {
cur ^= num;
res += cnt[cur];
cnt[cur] += 1;
}
return res;
}
};
python3代码如下,
class Solution:
def beautifulSubarrays(self, nums: List[int]) -> int:
cnt = collections.defaultdict(int) #前缀异或和的出现个数
res = 0
cur = 0
cnt[0] = 1
for num in nums:
cur ^= num
res += cnt[cur]
cnt[cur] += 1
return res
题目28:2564. 子字符串异或查询
解题思路:预处理出所有值t
(0 <= t <= 1e9
)的最佳答案[left,right]
。然后代入,即可。
C++代码如下,
class Solution {
public:
vector<vector<int>> substringXorQueries(string s, vector<vector<int>>& queries) {
unordered_map<int,pair<int,int>> m;
if (s.find("0") != string::npos) {
int left = s.find("0");
m[0] = make_pair(left,left);
}
int n = s.size();
for (int i = 0; i < n; ++i) {
if (s[i] == '0') continue; //去除前导零,比如"010"与"10",优先选择"10"
int cur = 0;
for (int j = i; j < min(i+31,n); ++j) {
//[i,j]的值
cur *= 2;
if (s[j] == '1') cur += 1;
if (m.find(cur) == m.end()) {
m[cur] = make_pair(i,j);
}
}
}
vector<vector<int>> res;
for (auto query : queries) {
int t = query[0] ^ query[1];
if (m.find(t) == m.end()) {
res.push_back({-1,-1});
} else {
vector<int> ans = {m[t].first, m[t].second};
res.push_back(ans);
}
}
return res;
}
};
python3代码如下,
class Solution:
def substringXorQueries(self, s: str, queries: List[List[int]]) -> List[List[int]]:
#预处理出每个值t的[left,right],注意如果有多个答案,选择left最小的那个
m = collections.defaultdict(list)
if s.find("0") != -1:
left = s.find("0")
m[0] = [left,left]
n = len(s)
for i in range(n):
if s[i] == "0":
continue #去除前导0,比如"010"和"10",优先选择"10"
cur = 0
for j in range(i,min(i+31,n)):
#求[i,j]的大小
cur *= 2
if s[j] == "1":
cur += 1
if cur not in m:
m[cur] = [i,j]
res = []
for x,y in queries:
t = x ^ y
if t in m:
res.append(m[t])
else:
res.append([-1,-1])
return res
#超时版本
class Solution:
def substringXorQueries(self, s: str, queries: List[List[int]]) -> List[List[int]]:
res = []
for x,y in queries:
t = x ^ y
#求t的二进制表示s1
s1 = ""
if t == 0:
s1 = "0"
else:
for i in range(32):
if (1 << i) > t:
break
if (t >> i) & 1:
s1 += "1"
else:
s1 += "0"
s1 = s1[::-1] #翻转字符串
if s.find(s1) == -1:
res.append([-1,-1])
else:
left = s.find(s1)
right = left + len(s1) - 1
res.append([left,right])
return res
题目29:1734. 解码异或后的排列
解题思路:先计算出a[0]^a[1]^...^a[n-1]
的值t1
,然后计算出a[0]^a[1]^...^a[n-2]
的值t2
,则a[n-1]=t1^t2
,依次计算出a[n-2],a[n-3],...,a[0]
的值。
C++代码如下,
class Solution {
public:
vector<int> decode(vector<int>& encoded) {
int n = encoded.size() + 1;
//计算a[0]^a[1]^...^a[n-1]的值t1
int t1 = 0;
for (int i = 1; i < n+1; ++i) {
t1 ^= i;
}
//计算a[0]^a[1]^...^a[n-2]的值t2
int t2 = 0;
for (int i = 0; i < n-1; i += 2) {
t2 ^= encoded[i];
}
//计算出a[n-1]=t1^t2
vector<int> a(n, 0);
a[n-1] = t1^t2;
for (int i = n-2; i >= 0; --i) {
a[i] = encoded[i] ^ a[i+1];
}
return a;
}
};
python3代码如下,
class Solution:
def decode(self, encoded: List[int]) -> List[int]:
#计算a[0]^a[1]^...^a[n-1]的值t1
n = len(encoded) + 1
t1 = 0
for x in range(1,n+1):
t1 ^= x
#计算a[0]^a[1]^...^a[n-2]的值t2
t2 = 0
for i in range(0,n-1,2):
t2 ^= encoded[i]
#计算a[n-1]
a = [0] * n
a[n-1] = t1 ^ t2
for i in range(n-2,-1,-1):
a[i] = encoded[i] ^ a[i+1]
return a
题目30:2857. 统计距离为 k 的点对
解题思路:考虑k
的最大值为100。那么如果(x1,y1)
已选择,则遍历x1^x2
的结果值i
,0<=i<=k
,可以计算(x1^i,y1^(k-i))
的出现次数。
C++代码如下,
//使用map也可以通过
class Solution {
public:
int countPairs(vector<vector<int>>& coordinates, int k) {
map<pair<int,int>, int> cnt;
int res = 0;
for (auto &coordinate : coordinates) {
int x = coordinate[0];
int y = coordinate[1];
for (int i = 0; i < k+1; ++i) {
auto it = cnt.find(make_pair(x^i,y^(k-i)));
if (it != cnt.end()) { //避免往cnt中插入过多的数据
res += it->second;
}
}
cnt[make_pair(x,y)] += 1;
}
return res;
}
};
class Solution {
public:
int countPairs(vector<vector<int>>& coordinates, int k) {
unordered_map<long long, int> cnt;
long long a = 2000000;
int res = 0;
for (auto &coordinate : coordinates) {
int x = coordinate[0];
int y = coordinate[1];
for (int i = 0; i < k+1; ++i) {
long long key1 = 1ll * (x ^ i) * a + y ^ (k-i);
auto it = cnt.find(key1);
if (it != cnt.end()) { //避免往cnt中插入过多的数据
res += it->second;
}
}
long long key2 = 1ll * x * a + y;
cnt[key2] += 1;
}
return res;
}
};
python3代码如下,
class Solution:
def countPairs(self, coordinates: List[List[int]], k: int) -> int:
cnt = collections.defaultdict(int)
res = 0
for x, y in coordinates:
for i in range(k+1):
res += cnt[(x^i, y^(k-i))]
cnt[(x,y)] += 1
return res
#暴力解法
class Solution:
def countPairs(self, coordinates: List[List[int]], k: int) -> int:
res = 0
#暴力解法
n = len(coordinates)
for i in range(n):
x1,y1 = coordinates[i]
for j in range(i+1,n):
x2,y2 = coordinates[j]
val = (x1 ^ x2) + (y1 ^ y2)
if val == k:
res += 1
return res
解题思路:前缀字典树。
C++代码如下,
class TrieNode {
public:
TrieNode* children[2] = {nullptr, nullptr};
int sum = 0;
TrieNode() : sum(0) {}
};
class Trie {
private:
TrieNode* root = new TrieNode();
static constexpr int HIGH_BIT = 14;
public:
void add(int x) {
//将数x插入到前缀字典树中
TrieNode* cur = root;
for (int i = HIGH_BIT; i >= 0; --i) {
int bit = (x >> i) & 1;
if (cur->children[bit] == nullptr) {
cur->children[bit] = new TrieNode();
}
cur = cur->children[bit];
cur->sum += 1;
}
return;
}
int get(int x, int limit) {
//从前缀字典树中找到y,使得y^x <= limit,求有多少个这样的y
int res = 0;
TrieNode* cur = root;
for (int i = HIGH_BIT; i >= 0; --i) {
int bit = (x >> i) & 1;
if ((limit >> i) & 1) {
//limit的第i为1,从高位14开始数
if (cur->children[bit] != nullptr) {
res += cur->children[bit]->sum;
}
if (cur->children[bit^1] == nullptr) {
return res;
}
cur = cur->children[bit^1];
} else {
//limit的第i位为0,从高位14开始数
if (cur->children[bit] == nullptr) {
return res;
}
cur = cur->children[bit];
}
}
res += cur->sum;
return res;
}
};
class Solution {
public:
int countPairs(vector<int>& nums, int low, int high) {
function<int(int)> f =[&] (int limit) -> int {
int res = 0;
int n = nums.size();
Trie trie = Trie();
for (int i = 0; i < n-1; ++i) {
trie.add(nums[i]);
res += trie.get(nums[i+1], limit);
}
return res;
};
return f(high) - f(low-1);
}
};
python3代码如下,
HIGH_BIT = 14
class TrieNode:
def __init__(self):
self.children = [None, None]
self.sum = 0
class Trie:
def __init__(self):
self.root = TrieNode()
def add(self, x: int) -> None:
#往前缀trie树中插入数x
cur = self.root
for i in range(HIGH_BIT, -1, -1):
bit = (x >> i) & 1
if not cur.children[bit]:
cur.children[bit] = TrieNode()
cur = cur.children[bit]
cur.sum += 1
return
def get(self, x: int, limit: int) -> int:
#从前缀trie树中找到y,使得y^x <= limit,返回这样的y的个数
res = 0
cur = self.root
for i in range(HIGH_BIT, -1, -1):
bit = (x >> i) & 1
if (limit >> i) & 1:
if cur.children[bit]:
#字典树中y^x的值,与limit进行比较
#记HIGH_BIT-i为k
#前k-1位相同,但第k位不同,y^x的第k为0,而limit的第k位为1
res += cur.children[bit].sum
if not cur.children[bit^1]:
#字典树中y^x的值,与limit进行比较
#记HIGH_BIT-i为k
#前k位都相同的数,它不存在
return res
cur = cur.children[bit^1]
else:
#记HIGH_BIT-i为k
#limit的第k位为0
#y^X的第k位的数只能为0
if not cur.children[bit]:
#字典树中y^x的值,与limit进行比较
#记HIGH_BIT-i为k
#前k位都相同的数,它不存在
return res
cur = cur.children[bit]
res += cur.sum #加上末尾结点的值
return res
class Solution:
def countPairs(self, nums: List[int], low: int, high: int) -> int:
def f(limit: int) -> int:
#nums中nums[i]^nums[j]<=limit,且i<j的(i,j)的个数
res = 0
trie = Trie()
n = len(nums)
for i in range(n-1):
trie.add(nums[i])
res += trie.get(nums[i+1], limit)
return res
return f(high) - f(low-1)
class Solution:
def countPairs(self, nums: List[int], low: int, high: int) -> int:
#暴力解法
n = len(nums)
res = 0
for i in range(n):
for j in range(i+1,n):
x = nums[i] ^ nums[j]
if low <= x <= high:
res += 1
return res
2.3 与或(AND/OR)的性质
AND的数越多,结果越小。OR的数越多,结果越大。
题目32:2980. 检查按位或是否存在尾随零
解题思路:模拟。
C++代码如下,
class Solution {
public:
bool hasTrailingZeros(vector<int>& nums) {
//存在两个偶数即可
int cnt = 0;
for (auto num : nums) {
if ((num & 1) == 0) {
cnt += 1;
if (cnt >= 2) return true;
}
}
return false;
}
};
python3代码如下,
class Solution:
def hasTrailingZeros(self, nums: List[int]) -> bool:
#只要存在两个偶数,就返回true
cnt = 0
for num in nums:
if not num & 1:
cnt += 1
if cnt >= 2:
return True
return False
题目33:1318. 或运算的最小翻转次数
解题思路:模拟。
C++代码如下,
class Solution {
public:
int minFlips(int a, int b, int c) {
int t = a | b;
int cnt = 0;
for (int i = 0; i < 31; ++i) {
int bit1 = (t >> i) & 1;
int bit2 = (c >> i) & 1;
if (bit1 != bit2) {
if (bit2 == 1) {
cnt += 1;
} else {
//bit2 == 0
if ((a >> i) & 1) cnt += 1;
if ((b >> i) & 1) cnt += 1;
}
}
}
return cnt;
}
};
python3代码如下,
class Solution:
def minFlips(self, a: int, b: int, c: int) -> int:
cnt = 0
t = a | b
for i in range(31):
bit1 = (t >> i) & 1
bit2 = (c >> i) & 1
if bit1 != bit2:
if bit2 == 1:
cnt += 1
else:
#bit2 == 0
if (a >> i) & 1:
cnt += 1
if (b >> i) & 1:
cnt += 1
return cnt
题目34:2419. 按位与最大的最长子数组
解题思路:与越多,值越小。
C++代码如下,
class Solution {
public:
int longestSubarray(vector<int>& nums) {
int max_x = ranges::max(nums);
int res = 1;
int i = 0;
int n = nums.size();
while (i < n) {
if (nums[i] == max_x) {
int j = i;
while (j < n && nums[j] == max_x) {
j += 1;
}
//[i,j)
res = max(res, j-i);
i = j; //更新i
} else {
i += 1; //更新i
}
}
return res;
}
};
python3代码如下,
class Solution:
def longestSubarray(self, nums: List[int]) -> int:
max_x = max(nums)
n = len(nums)
res = 1
i = 0
while i < n:
if nums[i] == max_x:
j = i
while j < n and nums[j] == max_x:
j += 1
#[i,j)
res = max(res, j-i)
i = j #更新i
else:
i += 1
return res
题目35:2871. 将数组分割成最多数目的子数组
解题思路:当最小分数为0时,才可以拆分数组。
C++代码如下,
class Solution {
public:
int maxSubarrays(vector<int>& nums) {
int INI = 0xffffffff;
int target = INI;
for (auto num : nums) target &= num;
if (target > 0) { //特判
return 1;
}
//只有target为0时,才可以拆分数组
int res = 0;
int cur = INI;
for (auto num : nums) {
cur &= num;
if (cur == 0) {
res += 1;
cur = INI;
}
}
return res;
}
};
python3代码如下,
class Solution:
def maxSubarrays(self, nums: List[int]) -> int:
INI = 0
for i in range(31):
INI += 1 << i
n = len(nums)
target = INI
for num in nums:
target &= num
#target就是子数组的最小分数
if target > 0: #特判
return 1
#只有最小分数为0时,才可以拆分数组
res = 0
cur = INI
for num in nums:
cur &= num
if cur == 0:
res += 1
cur = INI
return res
题目36:2401. 最长优雅子数组
解题思路:滑动窗口。二进制表示31位中,每一位只能有一个下标。
C++代码如下,
class Solution {
public:
int longestNiceSubarray(vector<int>& nums) {
int cnt[31] = {-1};
for (int i = 0; i < 31; ++i) cnt[i] = -1;
int res = 1;
int n = nums.size();
int prev = -1;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < 31; ++j) {
if ((nums[i] >> j) & 1) {
prev = max(prev, cnt[j]);
cnt[j] = i; //二进制表示的第j位,被nums数组中的第i位占住了
}
}
//(prev,i]
res = max(res, i-prev);
}
return res;
}
};
python3代码如下,
class Solution:
def longestNiceSubarray(self, nums: List[int]) -> int:
#任意两个数的与,都为0
n = len(nums)
res = 1
cnt = [-1] * 31
prev = -1
for i in range(n):
#把nums[i]添加至cnt中
for j in range(31):
if (nums[i] >> j) & 1:
prev = max(prev, cnt[j])
cnt[j] = i
#(prev,i]
res = max(res, i-prev)
return res
题目37:3133. 数组最后一个元素的最小值
解题思路:模拟。n-1
的二进制表示,填入x
的二进制表示中非1的位置处。
C++代码如下,
class Solution {
public:
long long minEnd(int n, int x) {
int cnt[63] = {0};
for (int i = 0; i < 63; ++i) cnt[i] = 0;
//将x的二进制填入cnt中
for (int i = 0; i < 31; ++i) {
if ((x >> i) & 1) cnt[i] = 1;
}
//将n-1的二进制填入cnt中,注意已填入1的地方不能再填入数字
//注意去掉前导零
int j = 0;
int t = n-1;
for (int i = 0; i < 31; ++i) {
if ((1 << i) > t) break;
int bit = (t >> i) & 1;
while (j < 63 && cnt[j] == 1) j += 1;
cnt[j] = bit;
j += 1; //已经填入的不能再填
}
long long res = 0;
for (int i = 0; i < 63; ++i) {
if (cnt[i] == 1) {
res += 1ll << i;
}
}
return res;
}
};
python3代码如下,
class Solution:
def minEnd(self, n: int, x: int) -> int:
#数组严格单调递增
#数组按位与的结果为x
#数组nums[n-1]值最小,返回这个最小值
#x,...
#n-1的二进制表示
#填入x的二进制表示中非1的位置处
BIT_MAX = 63
cnt = [0] * BIT_MAX
for i in range(BIT_MAX):
if (x >> i) & 1:
cnt[i] = 1
t = n - 1
j = 0
for i in range(BIT_MAX):
if (1 << i) > t:
break #提前中断for循环
bit = (t >> i) & 1
while j < BIT_MAX and cnt[j] == 1:
j += 1
cnt[j] = bit
j += 1 #第j位不能再填入了
res = 0
for i in range(BIT_MAX):
if cnt[i] == 1:
res += 1 << i
return res
题目38:2680. 最大或值
解题思路:k
次操作全都施加在某一个元素上。
C++代码如下,
class Solution {
public:
long long maximumOr(vector<int>& nums, int k) {
int n = nums.size();
vector<long long> suffix(n+1, 0);
for (int i = n-1; i >= 0; --i) {
suffix[i] = suffix[i+1] | nums[i];
}
long long res = 0;
long long cur = 0;
for (int i = 0; i < n; ++i) {
long long ans = 1ll * cur | ((1ll * nums[i]) << k) | suffix[i+1];
res = max(res, ans);
cur |= nums[i];
}
return res;
}
};
python3代码如下,
class Solution:
def maximumOr(self, nums: List[int], k: int) -> int:
#k次操作全都施加在某一个元素上
n = len(nums)
suffix = [0] * (n+1) #[i,n-1]的后缀或之和为suffix[i]
for i in range(n-1,-1,-1):
suffix[i] = suffix[i+1] | nums[i]
res = 0
cur = 0
for i in range(n):
ans = cur | (nums[i] << k) | suffix[i+1]
res = max(res, ans)
cur |= nums[i]
return res
题目39:3108. 带权图里旅途的最小代价
解题思路:并查集。参与与运算的数越多,其值越小。
C++代码如下,
class Solution {
public:
vector<int> minimumCost(int n, vector<vector<int>>& edges, vector<vector<int>>& query) {
vector<int> p(n, 0);
for (int i = 0; i < n; ++i) p[i] = i;
function<int(int)> find =[&] (int x) -> int {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
};
for (auto edge : edges) {
int a = edge[0], b = edge[1], w = edge[2];
int pa = find(a);
int pb = find(b);
if (pa != pb) {
p[pa] = pb;
}
}
unordered_map<int, int> map_id_score;
for (auto edge: edges) {
int a = edge[0];
int pa = find(a);
if (map_id_score.find(pa) == map_id_score.end()) {
map_id_score[pa] = edge[2];
} else {
map_id_score[pa]= map_id_score[pa] & edge[2];
}
}
vector<int> res;
for (auto ele : query) {
int a = ele[0];
int b = ele[1];
int pa = find(a);
int pb = find(b);
if (pa != pb) res.push_back(-1);
else {
res.push_back(map_id_score[pa]);
}
}
return res;
}
};
python3代码如下,
class Solution:
def minimumCost(self, n: int, edges: List[List[int]], query: List[List[int]]) -> List[int]:
#计算并查集
p = [0] * n
#初始化
for i in range(n):
p[i] = i
def find(x: int) -> int:
if p[x] != x:
p[x] = find(p[x])
return p[x]
for a,b,_ in edges:
pa = find(a)
pb = find(b)
if pa != pb:
p[pa] = pb
INI = 0
for i in range(31):
INI += 1 << i
map_id_score = collections.defaultdict(int)
for a,b,w in edges:
pa = find(a)
if pa in map_id_score:
map_id_score[pa] = map_id_score[pa] & w
else:
map_id_score[pa] = w
res = []
for a,b in query:
pa = find(a)
pb = find(b)
if pa != pb:
res.append(-1)
else:
res.append(map_id_score[pa])
return res
题目40:3117. 划分数组得到最小的值之和
解题思路:记忆化搜索。从i
开始,划分第j
个子数组,之前与的值为andVal
。该情况下所能获得的最小值。
C++代码如下,
C++需要注意auto dfs =[&](auto&& dfs, int i, int j, int andVal) -> int {...};
的用法比function<int(int,int,int)> dfs =[&] (int i, int j, int andVal) -> int {...};
运行速度快。
class Solution {
public:
int minimumValueSum(vector<int>& nums, vector<int>& andValues) {
int n = nums.size();
int m = andValues.size();
const int inf = 0x3f3f3f3f;
unordered_map<long long, int> memo;
auto dfs =[&] (auto&& dfs, int i, int j, int andVal) -> int {
if (n-i < m-j) {
return inf;
}
if (j == m) {
if (i == n) {
return 0;
} else {
return inf;
}
}
andVal &= nums[i]; //C++代码注意"addVal的更新"与"在memo中查找mask"的先后顺序
long long mask = ((i * 1ll) << 36) | ((j * 1ll) << 32) | andVal;
if (memo.find(mask) != memo.end()) return memo[mask];
int res = dfs(dfs,i+1,j,andVal); //第j个子数组不以nums[i]为结尾
if (andVal == andValues[j]) { //第j个子数组以nums[i]为结尾
res = min(res, dfs(dfs,i+1,j+1,-1) + nums[i]);
}
memo[mask] = res;
return memo[mask];
};
int ans = dfs(dfs,0,0,-1);
if (ans == inf) return -1;
else return ans;
}
};
//超出时间限制
class Solution {
public:
int minimumValueSum(vector<int>& nums, vector<int>& andValues) {
int n = nums.size();
int m = andValues.size();
const int inf = 0x3f3f3f3f;
unordered_map<long long, int> memo;
function<int(int,int,int)> dfs =[&] (int i, int j, int andVal) -> int {
if (n-i < m-j) {
return inf;
}
if (j == m) {
if (i == n) {
return 0;
} else {
return inf;
}
}
andVal &= nums[i]; //C++代码注意"addVal的更新"与"在memo中查找mask"的先后顺序
long long mask = ((i * 1ll) << 36) | ((j * 1ll) << 32) | andVal;
if (memo.contains(mask)) return memo[mask];
int res = dfs(i+1,j,andVal); //第j个子数组不以nums[i]为结尾
if (andVal == andValues[j]) { //第j个子数组以nums[i]为结尾
res = min(res, dfs(i+1,j+1,-1) + nums[i]);
}
memo[mask] = res;
return memo[mask];
};
int ans = dfs(0,0,-1);
if (ans == inf) return -1;
else return ans;
}
};
python3代码如下,
class Solution:
def minimumValueSum(self, nums: List[int], andValues: List[int]) -> int:
n, m = len(nums), len(andValues)
@cache
def dfs(i: int, j: int, andVal: int) -> int:
#从i开始划分,划分第j个子数组,前面划分的值为andVal
#该情况下,能够得到的最小的代价
if n-i < m-j:
return inf
if j == m:
if i == n:
return 0
else: #i < n
return inf
andVal &= nums[i]
res = dfs(i+1, j, andVal) #不以nums[i]结尾
if andVal == andValues[j]: #以nums[i]结尾
res = min(res, dfs(i+1,j+1,-1) + nums[i])
return res
ans = dfs(0,0,-1)
if ans == inf:
return -1
else:
return ans
2.4 LogTrick
题目41:3209. 子数组按位与值为 K 的数目
解题思路:logtrick和二分。例题1。
C++代码如下,
class Solution {
public:
long long countSubarrays(vector<int>& nums, int k) {
long long res = 0;
int n = nums.size();
for (int i = 0; i < n; ++i) {
int x = nums[i];
for (int j = i-1; j >= 0; --j) {
if ((nums[j] & x) == nums[j]) break;
//如果nums[j]&x的值为nums[j],那么后面的也不会改变,因为第i-1次遍历时nums[j-1] = nums[j-1] & nums[j]。它们已经做了操作。
//所以没有必要做后续更新了。break掉。
nums[j] &= x;
}
auto iter1 = upper_bound(nums.begin(),nums.begin()+i+1,k);
auto iter2 = lower_bound(nums.begin(),nums.begin()+i+1,k);
res += distance(iter2,iter1);
}
return res;
}
};
python3代码如下,
class Solution:
def countSubarrays(self, nums: List[int], k: int) -> int:
res = 0
for i,x in enumerate(nums):
for j in range(i-1,-1,-1):
if nums[j] & x == nums[j]:
break
nums[j] &= x
res += bisect_right(nums, k, 0, i+1) - bisect_left(nums, k, 0, i+1)
return res
题目42:2411. 按位或最大的最小子数组长度
解题思路:前缀和、二分、logtrick。例题2。
C++代码如下,
class Solution {
public:
vector<int> smallestSubarrays(vector<int>& nums) {
int n = nums.size();
vector<int> res(n, 1);
for (int i = 0; i < n; ++i) {
int x = nums[i];
for (int j = i-1; j >= 0; --j) {
if ((x | nums[j]) == nums[j]) break;
nums[j] |= x;
res[j] = i-j+1;
}
}
return res;
}
};
class Solution {
public:
vector<int> smallestSubarrays(vector<int>& nums) {
int n = nums.size();
vector<vector<int>> cnt(n+1, vector<int>(31, 0)); //1的个数
for (int i = 0; i < n; ++i) {
for (int j = 0; j < 31; ++j) {
if (nums[i] & (1 << j)) {
cnt[i+1][j] = cnt[i][j] + 1;
} else {
cnt[i+1][j] = cnt[i][j];
}
}
}
function<bool(int,int)> check =[&] (int i, int mid) -> bool {
for (int j = 0; j < 31; ++j) {
if (cnt[mid+1][j]-cnt[i][j] == 0 && cnt[n][j]-cnt[i][j] >= 1) return false;
}
return true;
};
vector<int> res(n, -1);
for (int i = 0; i < n; ++i) {
int left = i;
int right = n-1;
int ans = right;
while (left <= right) {
int mid = (left + right) / 2;
if (check(i,mid)) {
//找到满足要求的值
ans = mid;
right = mid-1;
} else {
left = mid+1;
}
}
res[i] = ans - i + 1;
}
return res;
}
};
python3代码如下,
class Solution:
def smallestSubarrays(self, nums: List[int]) -> List[int]:
n = len(nums)
res = [1] * n
for i,x in enumerate(nums):
for j in range(i-1,-1,-1):
if nums[j] | x == nums[j]:
break
nums[j] |= x
res[j] = i - j + 1
return res
class Solution:
def smallestSubarrays(self, nums: List[int]) -> List[int]:
n = len(nums)
cnt = [[0] * 31 for _ in range(n+1)]
for i in range(n):
for j in range(31):
if nums[i] & (1 << j):
cnt[i+1][j] = cnt[i][j] + 1
else:
cnt[i+1][j] = cnt[i][j]
res = [-1] * n
def check(i: int, mid: int) -> bool:
for j in range(31):
if (cnt[mid+1][j]-cnt[i][j]) == 0 and (cnt[n][j]-cnt[i][j]) >= 1:
return False
return True
for i in range(n):
#从[i,n-1]找到一个下标j,使得j满足条件
left = i
right = n-1
ans = n-1
while left <= right:
mid = (left + right) // 2
if check(i,mid):
#满足条件
ans = mid
right = mid-1
else:
left = mid+1
res[i] = ans - i + 1
return res
解题思路:logtrick。
C++代码如下,
class Solution {
public:
int minimumSubarrayLength(vector<int>& nums, int k) {
int n = nums.size();
const int inf = 0x3f3f3f3f;
int res = inf;
for (int i = 0; i < n; ++i) {
int x = nums[i];
if (x >= k) res = min(res, 1);
for (int j = i-1; j >= 0; --j) {
if ((nums[j] | x) == nums[j]) break;
nums[j] |= x;
if (nums[j] >= k) {
res = min(res, i-j+1);
}
}
}
return res == inf ? -1 : res;
}
};
python3代码如下,
class Solution:
def minimumSubarrayLength(self, nums: List[int], k: int) -> int:
n = len(nums)
res = inf
for i in range(n):
x = nums[i]
if x >= k:
res = min(res, 1)
for j in range(i-1,-1,-1):
if (x | nums[j]) == nums[j]:
break
nums[j] |= x
if nums[j] >= k:
res = min(res, i-j+1)
return -1 if res == inf else res
解题思路:logtrick。
C++代码如下,
class Solution {
public:
int minimumDifference(vector<int>& nums, int k) {
int n = nums.size();
int res = INT_MAX;
for (int i = 0; i < n; ++i) {
int x = nums[i];
res = min(res, abs(x-k));
for (int j = i-1; j >= 0; --j) {
if ((nums[j] | x) == nums[j]) break;
nums[j] |= x;
res = min(res, abs(nums[j]-k));
}
}
return res;
}
};
python3代码如下,
class Solution:
def minimumDifference(self, nums: List[int], k: int) -> int:
n = len(nums)
res = inf
for i in range(n):
x = nums[i]
res = min(res, abs(x-k))
for j in range(i-1,-1,-1):
if nums[j] | x == nums[j]:
break
nums[j] |= x
res = min(res, abs(nums[j]-k))
return res
题目45:1521. 找到最接近目标值的函数值
解题思路:logtrick。
C++代码如下,
class Solution {
public:
int closestToTarget(vector<int>& nums, int target) {
int n = nums.size();
int res = INT_MAX;
for (int i = 0; i < n; ++i) {
int x = nums[i];
res = min(res, abs(x-target));
for (int j = i-1; j >= 0; --j) {
if ((nums[j] & x) == nums[j]) break;
nums[j] &= x;
res = min(res, abs(nums[j]-target));
}
}
return res;
}
};
python3代码如下,
class Solution:
def closestToTarget(self, nums: List[int], target: int) -> int:
#[l,r]之间的与
n = len(nums)
res = inf
for i in range(n):
x = nums[i]
res = min(res, abs(x-target))
for j in range(i-1,-1,-1):
if nums[j] & x == nums[j]:
break
nums[j] &= x
res = min(res, abs(nums[j]-target))
return res
题目46:898. 子数组按位或操作
解题思路:logtrick。
C++代码如下,
class Solution {
public:
int subarrayBitwiseORs(vector<int>& nums) {
int n = nums.size();
set<int> set1;
for (int i = 0; i < n; ++i) {
int x = nums[i];
set1.insert(x);
for (int j = i-1; j >= 0; --j) {
if ((nums[j] | x) == nums[j]) break;
nums[j] |= x;
set1.insert(nums[j]);
}
}
return set1.size();
}
};
python3代码如下,
class Solution:
def subarrayBitwiseORs(self, nums: List[int]) -> int:
res = set()
n = len(nums)
for i in range(n):
x = nums[i]
res.add(x)
for j in range(i-1,-1,-1):
if nums[j] | x == nums[j]:
break
nums[j] |= x
res.add(nums[j])
return len(res)
2.5 拆位/贡献法
题目47:477. 汉明距离总和
解题思路:计算每一位的贡献。
C++代码如下,
class Solution {
public:
int totalHammingDistance(vector<int>& nums) {
int cnt0[31] = {0};
int cnt1[31] = {0};
memset(cnt0, 0, sizeof cnt0);
memset(cnt1, 0, sizeof cnt1);
for (auto num : nums) {
for (int i = 0; i < 31; ++i) {
if ((num >> i) & 1) cnt1[i] += 1;
else cnt0[i] += 1;
}
}
int res = 0;
for (int i = 0; i < 31; ++i) {
res += cnt0[i] * cnt1[i];
}
return res;
}
};
python3代码如下,
class Solution:
def totalHammingDistance(self, nums: List[int]) -> int:
cnt0 = [0] * 31 #cnt0[i]表示第i位为0的元素的个数
cnt1 = [0] * 31 #cnt1[i]表示第i位为1的元素的个数
for num in nums:
for i in range(31):
if (num >> i) & 1:
cnt1[i] += 1
else:
cnt0[i] += 1
res = 0
for i in range(31):
res += cnt0[i] * cnt1[i]
return res
题目48:1863. 找出所有子集的异或总和再求和
解题思路:数学公式推导。数组nums
中总共有个数,考虑二进制表示的第i
位,有a
个数的第i
位为0,有b = n - a
个数的第i
位为1。那么第i
位的贡献为,cnt
为异或结果值第i
为1的子集数目。它包含两部分,从a
个数中选取奇数个数 + 从b
个数中随机选择。即,
其中为小于等于的最大的奇数。可以推出,
那么,
也就是说,二进制表示中第i
位的数目a
与其贡献无关。
证明1:
考虑,
令有,
令有,
结合公式(1)和公式(2)可知,
即证!
C++代码如下,
class Solution {
public:
int subsetXORSum(vector<int>& nums) {
int a = 0;
int n = nums.size();
for (auto num : nums) a |= num;
int res = (1 << (n-1)) * a;
return res;
}
};
python3代码如下,
class Solution:
def subsetXORSum(self, nums: List[int]) -> int:
n = len(nums)
a = 0
for num in nums:
a |= num
res = (1 << (n-1)) * a
return res
题目49:2425. 所有数对的异或和
解题思路:
方法1思路:如果数组nums1
中的元素个数为奇数,那么res
需要异或上数组nums2
中的每一个元素。同理nums2
。
方法2思路:新生成的数组中元素个数是n*m
,其中第i
位为1的个数为cnt
,如果它为奇数,则最后的结果的二进制表示中第i
位为1,res += 1 << i
,否则贡献为0。cnt
的计算需要知道nums1
数组和nums2
数组中二进制表示中第i
位为1的个数和第i
位为0的个数。
C++代码如下,
class Solution {
public:
int xorAllNums(vector<int>& nums1, vector<int>& nums2) {
int res = 0;
int n = nums1.size();
int m = nums2.size();
if (n & 1) {
for (auto num : nums2) res ^= num;
}
if (m & 1) {
for (auto num : nums1) res ^= num;
}
return res;
}
};
class Solution {
public:
int xorAllNums(vector<int>& nums1, vector<int>& nums2) {
int cnt1[31][2] = {0};
memset(cnt1, 0, sizeof cnt1);
int cnt2[31][2] = {0};
memset(cnt2, 0, sizeof cnt2);
for (auto num : nums1) {
for (int i = 0; i < 31; ++i) {
if (num & (1 << i)) {
cnt1[i][1] += 1;
} else {
cnt1[i][0] += 1;
}
}
}
for (auto num : nums2) {
for (int i = 0; i < 31; ++i) {
if (num & (1 << i)) {
cnt2[i][1] += 1;
} else {
cnt2[i][0] += 1;
}
}
}
int res = 0;
for (int i = 0; i < 31; ++i) {
long long x = 1ll * cnt1[i][0] * cnt2[i][1] + 1ll * cnt1[i][1] * cnt2[i][0];
if (x & 1) res += 1 << i;
}
return res;
}
};
python3代码如下,
class Solution:
def xorAllNums(self, nums1: List[int], nums2: List[int]) -> int:
n = len(nums1)
m = len(nums2)
res = 0
if n & 1:
for num in nums2:
res ^= num
if m & 1:
for num in nums1:
res ^= num
return res
class Solution:
def xorAllNums(self, nums1: List[int], nums2: List[int]) -> int:
cnt1 = [[0,0] for _ in range(31)]
cnt2 = [[0,0] for _ in range(31)]
for num in nums1:
for i in range(31):
if num & (1 << i):
cnt1[i][1] += 1
else:
cnt1[i][0] += 1
for num in nums2:
for i in range(31):
if num & (1 << i):
cnt2[i][1] += 1
else:
cnt2[i][0] += 1
res = 0
for i in range(31):
x = cnt1[i][0] * cnt2[i][1] + cnt1[i][1] * cnt2[i][0]
if x & 1:
res += 1 << i
return res
题目50:2275. 按位与结果大于零的最长组合
解题思路如下:计算数组nums
中元素满足"二进制表示中第i
位为1"的元素的个数。
C++代码如下,
class Solution {
public:
int largestCombination(vector<int>& candidates) {
int cnt[31] = {0};
memset(cnt, 0, sizeof cnt);
for (auto num : candidates) {
for (int i = 0; i < 31; ++i) {
if (num & (1 << i)) {
cnt[i] += 1;
}
}
}
int maxv = 0;
for (int i = 0; i < 31; ++i) maxv = max(maxv, cnt[i]);
return maxv;
}
};
python3代码如下,
class Solution:
def largestCombination(self, candidates: List[int]) -> int:
cnt = [0] * 31
for num in candidates:
for i in range(31):
if num & (1 << i):
cnt[i] += 1
return max(cnt)
题目51:1835. 所有数对按位与结果的异或和
解题思路:新列表中有个元素,求这个列表中的元素,满足第i
位为1的元素个数为。如果这个个数是奇数,那么最终结果二进制表示中第i
位为1,否则为0。
C++代码如下,
class Solution {
public:
int getXORSum(vector<int>& arr1, vector<int>& arr2) {
int a[31] = {0};
memset(a, 0, sizeof a);
int b[31] = {0};
memset(b, 0, sizeof b);
for (auto num : arr1) {
for (int i = 0; i < 31; ++i) {
if (num & (1 << i)) {
a[i] += 1;
}
}
}
for (auto num : arr2) {
for (int i = 0; i < 31; ++i) {
if (num & (1 << i)) {
b[i] += 1;
}
}
}
int res = 0;
for (int i = 0; i < 31; ++i) {
if ((1ll*a[i]*b[i]) & 1) res += 1 << i;
}
return res;
}
};
python3代码如下,
class Solution:
def getXORSum(self, arr1: List[int], arr2: List[int]) -> int:
a = [0] * 31
b = [0] * 31
for num in arr1:
for i in range(31):
if num & (1 << i):
a[i] += 1
for num in arr2:
for i in range(31):
if num & (1 << i):
b[i] += 1
res = 0
for i in range(31):
if (a[i]*b[i]) & 1:
res += 1 << i
return res
题目52:3153. 所有数对中数位差之和
解题思路:不同位数的数目。遍历十进制中的每一位。
C++代码如下,
class Solution {
public:
long long sumDigitDifferences(vector<int>& nums) {
long long res = 0;
for (int k = 0; k < 10; ++k) {
//十进制表示中的第k位
int base = (int)pow(10,k);
unordered_map<int,int> cnt;
for (auto num : nums) {
int x = (num / base) % 10;
cnt[x] += 1;
}
vector<int> keys;
for (auto [key,_] : cnt) keys.push_back(key);
int n = keys.size();
for (int i = 0; i < n; ++i) {
int x = keys[i];
for (int j = i+1; j < n; ++j) {
int y = keys[j];
res += 1ll * int(x!=y) * cnt[x] * cnt[y];
}
}
}
return res;
}
};
python3代码如下,
class Solution:
def sumDigitDifferences(self, nums: List[int]) -> int:
res = 0
for k in range(0,10):
#十进制表示中第k位的数
base = int(10**k)
cnt = collections.defaultdict(int)
for num in nums:
x = (num // base) % 10
cnt[x] += 1
ls = list(cnt.keys())
n = len(ls)
for i in range(n):
x = ls[i]
for j in range(i+1,n):
y = ls[j]
res += int(x!=y)*cnt[x]*cnt[y]
return res
2.5 试填法
解题思路:数位DP。二分。
C++代码如下,
class Solution {
public:
long long findMaximumNumber(long long k, int x) {
function<bool(long long)> check =[&] (long long mid) -> bool {
string s = bitset<64>(mid).to_string();
int n = s.size();
long long memo[68][68];
memset(memo, -1, sizeof memo);
function<long long(long long,long long,bool)> dfs =[&] (long long i, long long curr, bool is_limit) -> long long {
if (!is_limit && memo[i][curr] != -1) {
return memo[i][curr];
}
if (i == n) {
return curr;
}
long long res = 0;
int low = 0;
int up = is_limit ? s[i]-'0' : 1;
for (int d = low; d < up+1; ++d) {
long long dcurr = 0;
if (d == 1 && (n-i) % x == 0) {
dcurr = 1;
}
res += dfs(i+1, curr+dcurr, is_limit && up == d);
}
if (!is_limit) {
memo[i][curr] = res;
}
return res;
};
return dfs(0,0,true) <= k;
};
long long left = 0;
long long right = 1e15;
long long res = -1;
while (left <= right) {
long long mid = (left + right) / 2;
if (check(mid)) {
//满足总价值<=k
res = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return res;
}
};
python3代码如下,
class Solution:
def findMaximumNumber(self, k: int, x: int) -> int:
def check(mid: int) -> bool:
s = bin(mid)[2:]
n = len(s)
@cache
def dfs(i: int, curr: int, is_limit: bool) -> int:
#计算1~mid的数字的总价值
if i == n:
return curr
res = 0
low = 0
up = int(s[i]) if is_limit else 1
for d in range(low,up+1):
dcurr = 0
if d == 1 and (n-i) % x == 0:
dcurr = 1
res += dfs(i+1,curr+dcurr,is_limit and d == up)
return res
return dfs(0,0,True) <= k
left = 0
right = int(1e15)
res = -1
while left <= right:
mid = (left + right) // 2
if check(mid):
res = mid
left = mid + 1
else:
right = mid - 1
return res
题目54:421. 数组中两个数的最大异或值
解题思路:trie树。
C++代码如下,
struct TrieNode {
TrieNode* children[2] = {nullptr, nullptr};
TrieNode() {
children[0] = nullptr;
children[1] = nullptr;
}
};
class Solution {
public:
int findMaximumXOR(vector<int>& nums) {
TrieNode* trie = new TrieNode();
int res = 0;
for (auto num : nums) {
//在trie中查找num
TrieNode* cur = trie;
int ans = 0;
for (int i = 31; i >= 0; --i) {
if (cur == nullptr) break;
int x = (num >> i) & 1;
if (cur->children[1-x] != nullptr) {
ans += 1 << i;
cur = cur->children[1-x];
} else {
cur = cur->children[x];
}
}
res = max(res, ans);
//把num写入到trie中
cur = trie; //重新将cur置为起始结点
for (int i = 31; i >= 0; --i) {
int x = (num >> i) & 1;
if (cur->children[x] == nullptr) {
cur->children[x] = new TrieNode();
}
cur = cur->children[x];
}
}
return res;
}
};
python3代码如下,
#方法1:trie树
class Solution:
def findMaximumXOR(self, nums: List[int]) -> int:
trie = {}
res = 0
for num in nums:
#从trie树中查找元素
ans = 0
cur = trie
for i in range(31,-1,-1):
x = (num >> i) & 1
if (1-x) in cur:
ans += (1 << i)
cur = cur[1-x]
else:
if x in cur:
cur = cur[x]
else:
break
res = max(res, ans) #更新res
#将num插入trie树中
cur = trie
for i in range(31,-1,-1):
x = (num >> i) & 1
if x in cur:
pass
else:
cur[x] = {}
cur = cur[x]
return res
题目55:2935. 找出强数对的最大异或值 II
解题思路:01-trie树、滑动区间。
C++代码如下,
struct TrieNode {
int cnt = 0;
TrieNode* children[2] = {nullptr, nullptr};
TrieNode(int val) : cnt(val) {}
};
class Trie {
private:
TrieNode* root = new TrieNode(0);
public:
void insert(int num) {
//往trie树中插入num
TrieNode* cur = root;
for (int i = 19; i >= 0; --i) {
int x = (num >> i) & 1;
if (cur->children[x] == nullptr) {
cur->children[x] = new TrieNode(0);
}
cur = cur->children[x];
cur->cnt += 1;
}
return;
}
void del(int num) {
//往trie树中删除num
TrieNode* cur = root;
for (int i = 19; i >= 0; --i) {
int x = (num >> i) & 1;
cur = cur->children[x];
cur->cnt -= 1;
}
return;
}
int search(int num) {
//在trie树中找到与num异或的最大值
int res = 0;
TrieNode* cur = root;
for (int i = 19; i >= 0; --i) {
int x = (num >> i) & 1;
if (cur->children[1-x] != nullptr && cur->children[1-x]->cnt != 0) {
res += 1 << i;
cur = cur->children[1-x];
} else {
cur = cur->children[x];
}
}
return res;
}
};
class Solution {
public:
int maximumStrongPairXor(vector<int>& nums) {
sort(nums.begin(), nums.end());
Trie trie = Trie();
int res = 0;
int left = 0;
for (auto y : nums) {
//找到2*x >= y的x,然后获得最佳目标值
trie.insert(y);
while (nums[left] * 2 < y) {
trie.del(nums[left]);
left += 1;
}
int ans = trie.search(y); //在trie树中找到与ans异或最大值
res = max(res, ans);
}
return res;
}
};
python3代码如下,
class TrieNode:
def __init__(self):
self.cnt = 0
self.children = [None, None]
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, num: int):
#把num插入到trie树中
cur = self.root
for i in range(19,-1,-1):
x = (num >> i) & 1
if cur.children[x] is None:
cur.children[x] = TrieNode()
cur = cur.children[x]
cur.cnt += 1
return
def delete(self, num: int):
#从trie树中删除num
cur = self.root
for i in range(19,-1,-1):
x = (num >> i) & 1
cur = cur.children[x]
cur.cnt -= 1
return
def search(self, num: int) -> int:
#在trie树中找到num的最大异或值
res = 0
cur = self.root
for i in range(19,-1,-1):
if cur is None:
break
x = (num >> i) & 1
if cur.children[1-x] is not None and cur.children[1-x].cnt != 0:
res += 1 << i
cur = cur.children[1-x]
else:
cur = cur.children[x]
return res
class Solution:
def maximumStrongPairXor(self, nums: List[int]) -> int:
nums.sort()
res = 0
left = 0
trie = Trie()
for y in nums:
#找到2x >= y的x集合,从这个集合中得到最佳答案
trie.insert(y)
while nums[left] * 2 < y:
trie.delete(nums[left])
left += 1
ans = trie.search(y)
res = max(res, ans)
return res
题目56:3145. 大数组元素的乘积
解题思路:
C++代码如下,
python3代码如下,