# LeetCode 2044. Count Number of Maximum Bitwise-OR Subsets https://leetcode.com/problems/count-number-of-maximum-bitwise-or-subsets/description/ ## 題目大意 給定整數陣列 `nums`,找出其某個子集的最大可能位元或運算結果(bitwise OR),並回傳具有該最大位元或運算結果的相異非空子集數量 ## 思考 最大的 bitwise OR 結果其實就是整個 `nums` 的元素都 bitwise OR 的結果 ### Algo 1 我們已經知道最大值了,接著就是窮舉所有可能,找出運算結果跟最大值一樣的子集就好 ```cpp! class Solution { public: int countMaxOrSubsets(vector<int> &nums) { const int n = nums.size(); const int maxOr = accumulate(nums.begin(), nums.end(), 0, bit_or<>()); int ans = 0; const int maxMask = 1 << n; for (int mask = 1; mask < maxMask; ++mask) { int curr = 0; for (int i = 0; i < n; ++i) { if (mask & (1 << i)) curr |= nums[i]; } if (curr == maxOr) ++ans; } return ans; } }; ``` 這樣的時間複雜度會是 $O(n\cdot 2^n)$ ,空間複雜度只有 $O(1)$ (所有的可能性有 $2^n$ 種) 由於題目說 `n` 不會超過 $16$ ,所以這樣的時間複雜度是可以接受的 ### Algo 2 說到窮舉所有可能,我們當然可以使用 backtracking 的技巧 ```cpp! class Solution { public: int countMaxOrSubsets(vector<int> &nums) { const int maxOr = accumulate(nums.begin(), nums.end(), 0, bit_or<>()); int ans = 0; helper(nums, 0, 0, maxOr, ans); return ans; } private: void helper(const vector<int> &nums, int i, int curr, const int &maxOr, int &ans) { if (i == nums.size()) { if (curr == maxOr) ++ans; return; } helper(nums, i + 1, curr, maxOr, ans); helper(nums, i + 1, curr | nums[i], maxOr, ans); } }; ``` 我們每次可以決定要或不要把 `nums[i]` 考慮並 bitwise OR 進去 ```cpp! helper(nums, i + 1, curr, maxOr, ans); // 不考慮 nums[i] helper(nums, i + 1, curr | nums[i], maxOr, ans); // 考慮 nums[i] ``` 這樣的時間複雜度是 $O(2^n)$ ,空間複雜度考慮到遞迴呼叫的 stack 使用的話也是 $O(2^n)$ 不過正如前面所講 `n` 很小,所以這樣的演算法是 OK 的 Go 的參考解答: ```go! func countMaxOrSubsets(nums []int) int { maxOr := 0 for _, num := range nums { maxOr |= num } ans := 0 helper(nums, 0, 0, maxOr, &ans) return ans } func helper(nums []int, i int, curr int, maxOr int, ans *int) { if i == len(nums) { if curr == maxOr { *ans++ } return } helper(nums, i+1, curr, maxOr, ans) helper(nums, i+1, curr|nums[i], maxOr, ans) } ```