灵神力扣题单之位运算

33 阅读36分钟

1 介绍

本博客用来记录灵神力扣题单之位运算

2 训练

2.1 基础题

题目12595. 奇偶位数

解题思路:模拟。

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]

题目2231. 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
        

题目3342. 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 
        

题目4476. 数字的补数

解题思路为:模拟。

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 

题目5191. 位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 
        

题目6338. 比特位计数

解题思路:模拟。

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

题目73226. 使两个整数相等的位更改次数

解题思路:模拟。

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 

题目81356. 根据数字二进制下 1 的数目排序

解题思路:模拟。

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 
        

题目9461. 汉明距离

解题思路:模拟。

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 

题目102220. 转换数字的最少位翻转次数

解题思路:模拟。

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 
        

题目11868. 二进制间距

解题思路:模拟。

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 
        

题目123211. 生成不含相邻零的二进制字符串

解题思路: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         

题目132917. 找出数组中的 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 

题目14693. 交替位二进制数

解题思路:模拟。

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 
        

题目152657. 找到两个数组的前缀公共数组

解题思路:模拟。

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)的性质

题目161486. 数组异或操作

解题思路:模拟即可。

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 

题目171720. 解码异或后的数组

解题思路:模拟即可。

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 
        

题目182433. 找出前缀异或的原始数组

解题思路:模拟即可。

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 
        

题目191310. 子数组异或查询

解题思路:前缀和。

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 

题目202683. 相邻值的按位异或

解题思路:模拟即可。

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
        

题目211829. 每个查询的最大异或值

解题思路:模拟。

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 

题目222997. 使数组异或和等于 K 的最少操作次数

解题思路:模拟。

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 
        

题目231442. 形成两个异或相等数组的三元组数目

解题思路:模拟。

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 
        

题目242429. 最小异或

解题思路:模拟。

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 

题目252527. 查询数组异或美丽值

解题思路:所有元素的异或和。

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 
        

题目262317. 操作后的最大异或和

解题思路:模拟即可。

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 
        

题目272588. 统计美丽子数组数目

解题思路:前缀异或和,哈希表。

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 
        

题目282564. 子字符串异或查询

解题思路:预处理出所有值t0 <= 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 

题目291734. 解码异或后的排列

解题思路:先计算出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 
        

题目302857. 统计距离为 k 的点对

解题思路:考虑k的最大值为100。那么如果(x1,y1)已选择,则遍历x1^x2的结果值i0<=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 

题目311803. 统计异或值在范围内的数对有多少

解题思路:前缀字典树。

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的数越多,结果越大。

题目322980. 检查按位或是否存在尾随零

解题思路:模拟。

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 
        

题目331318. 或运算的最小翻转次数

解题思路:模拟。

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 

题目342419. 按位与最大的最长子数组

解题思路:与越多,值越小。

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 

题目352871. 将数组分割成最多数目的子数组

解题思路:当最小分数为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 

题目362401. 最长优雅子数组

解题思路:滑动窗口。二进制表示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 
        

题目373133. 数组最后一个元素的最小值

解题思路:模拟。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 
        

题目382680. 最大或值

解题思路: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 

题目393108. 带权图里旅途的最小代价

解题思路:并查集。参与与运算的数越多,其值越小。

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 

题目403117. 划分数组得到最小的值之和

解题思路:记忆化搜索。从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

题目413209. 子数组按位与值为 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 

题目422411. 按位或最大的最小子数组长度

解题思路:前缀和、二分、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       

题目433097. 或值至少为 K 的最短子数组 II

解题思路: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 
        

题目443171. 找到按位或最接近 K 的子数组

解题思路: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 

题目451521. 找到最接近目标值的函数值

解题思路: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 
        

题目46898. 子数组按位或操作

解题思路: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 拆位/贡献法

题目47477. 汉明距离总和

解题思路:计算每一位的贡献。

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 
        

题目481863. 找出所有子集的异或总和再求和

解题思路:数学公式推导。数组nums中总共有nn个数,考虑二进制表示的第i位,有a个数的第i位为0,有b = n - a个数的第i位为1。那么第i位的贡献为2icnt2^i\cdot cntcnt为异或结果值第i为1的子集数目。它包含两部分,从a个数中选取奇数个数 + 从b个数中随机选择。即,

cnt=(Ca1+Ca3++Cak)2nacnt = (C_a^1+C_a^3+\cdots+C_a^k) \cdot 2^{n-a}

其中kk为小于等于aa的最大的奇数。可以推出,

Ca1+Ca3++Cak=2a1C_a^1+C_a^3+\cdots+C_a^k=2^{a-1}

那么,

cnt=2a12na=2n1cnt = 2^{a-1}\cdot 2^{n-a}=2^{n-1}

也就是说,二进制表示中第i位的数目a与其贡献无关。

证明1:

Ca1+Ca3++Cak=2a1C_a^1+C_a^3+\cdots+C_a^k=2^{a-1}

考虑,

(x+y)n=Cn0xny0+Cn1xn1y1++Cnkxnkyk++Cnnx0yn(x+y)^n=C_n^0x^ny^0+C_n^1x^{n-1}y^1+\cdots+C_n^kx^{n-k}y^k+\cdots+C_n^nx^0y^n

x=1,y=1x=1,y=1有,

2n=Cn0+Cn1++Cnk++Cnn(1)2^n=C_n^0+C_n^1+\cdots+C_n^k+\cdots+C_n^n \tag{1}

x=1,y=1x=1,y=-1有,

0=Cn0Cn1++Cnk(1)k++Cnn(1)n(2)0 = C_n^0-C_n^1+\cdots+C_n^k\cdot(-1)^k+\cdots+C_n^n\cdot(-1)^n \tag{2}

结合公式(1)和公式(2)可知,

Cn0+Cn2+Cn4+=Cn1+Cn3+Cn5+=2n1C_n^0+C_n^2+C_n^4+\cdots =C_n^1+C_n^3+C_n^5+\cdots=2^{n-1}

即证!

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 

题目492425. 所有数对的异或和

解题思路:

方法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 

题目502275. 按位与结果大于零的最长组合

解题思路如下:计算数组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)
        

题目511835. 所有数对按位与结果的异或和

解题思路:新列表中有n×mn\times m个元素,求这个列表中的元素,满足第i位为1的元素个数为a[i]b[i]a[i]\cdot b[i]。如果这个个数是奇数,那么最终结果二进制表示中第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 
        

题目523153. 所有数对中数位差之和

解题思路:不同位数的数目。遍历十进制中的每一位。

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 试填法

题目533007. 价值和小于等于 K 的最大数字

解题思路:数位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 
        

题目54421. 数组中两个数的最大异或值

解题思路: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 
                

题目552935. 找出强数对的最大异或值 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 

题目563145. 大数组元素的乘积

解题思路:

C++代码如下,

python3代码如下,

3 参考

灵神力扣题单