# 2044. Count Number of Maximum Bitwise-OR Subsets

[Leetcode](https://leetcode.com/problems/count-number-of-maximum-bitwise-or-subsets/)

Given an integer array `nums`, find the **maximum** possible **bitwise OR** of a subset of `nums` and return *the **number of different non-empty subsets** with the maximum bitwise OR*.

An array `a` is a **subset** of an array `b` if `a` can be obtained from `b` by deleting some (possibly zero) elements of `b`. Two subsets are considered **different** if the indices of the elements chosen are different.

The bitwise OR of an array `a` is equal to `a[0]`` `**`OR`**` ``a[1]`` `**`OR`**` ``...`` `**`OR`**` ``a[a.length - 1]` (**0-indexed**).

**Example 1:**

```
Input: nums = [3,1]
Output: 2
Explanation: The maximum possible bitwise OR of a subset is 3. There are 2 subsets with a bitwise OR of 3:
- [3]
- [3,1]
```

**Example 2:**

```
Input: nums = [2,2,2]
Output: 7
Explanation: All non-empty subsets of [2,2,2] have a bitwise OR of 2. There are 23 - 1 = 7 total subsets.
```

**Example 3:**

```
Input: nums = [3,2,1,5]
Output: 6
Explanation: The maximum possible bitwise OR of a subset is 7. There are 6 subsets with a bitwise OR of 7:
- [3,5]
- [3,1,5]
- [3,2,5]
- [3,2,1,5]
- [2,5]
- [2,1,5]
```

**Constraints:**

* `1 <= nums.length <= 16`
* `1 <= nums[i] <= 10^5`

### Basic Idea:

有两个思路，首先因为一共只有16个数字，所以即使暴力枚举所有的subsets也只需要O(2^16=65536)的时间复杂度，所以暴力解是行得通的。二则是可以使用DP的思路，利用如下递推公式。时间复杂度为O(len(nums) \* bitwise or 结果的数字范围)，当nums比较多的时候，复杂度会远优于brute force。

```
int[][] dp = new int[nums.length + 1][1<<17]
dp[0][0] = 1
for i from 0 to nums.length
    for j from 0 to 1<<17
        if (dp[i][j] > 0){
            dp[i + 1][j] += dp[i][j]
            dp[i + 1][nums[i] | j] += dp[i][j]
        }
    }
}

# dp[i][j] 表示到第i个数字为止，能够通过or产生的j的组合个数
```

#### Java Code：

```java
// DP 
class Solution {
    public int countMaxOrSubsets(int[] nums) {
        int N = 1<<17;
        int[] dp = new int[N];
        dp[0] = 1;
        for (int num : nums) {
            int[] dp2 = new int[N];
            for (int i = 0; i < dp.length; ++i) {
                if (dp[i] > 0) {
                    dp2[i | num] += dp[i];
                    dp2[i] += dp[i];
                }
            }
            dp = dp2;
        }
        int max = 0;
        int count = 0;
        for (int i = 0; i < N; ++i) {
            if (dp[i] > 0) {
                count = dp[i];
            }
        }
        return count;
    }
}

// Brute force
class Solution {
    public int countMaxOrSubsets(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        dfs(nums, 0, new ArrayList<>(), res);
        TreeMap<Integer, Integer> map = new TreeMap<>();
        for (List<Integer> list : res) {
            int curr = 0;
            for (int num : list) {
                curr |= num;
            }
            map.put(curr, map.getOrDefault(curr, 0) + 1);
        }
        return map.lastEntry().getValue();
    }
    
    private void dfs(int[] nums, int pos, List<Integer> path, List<List<Integer>> res) {
        res.add(new ArrayList<>(path));
        if (pos == nums.length) {
            return;
        }
        for (int i = pos; i < nums.length; ++i) {
            path.add(nums[i]);
            dfs(nums, i + 1, path, res);
            path.remove(path.size() - 1);
        }
    }
}
```
