|
| 1 | +# Bitwise ORs of Subarrays - Problem #898 |
| 2 | + |
| 3 | +## Problem Statement |
| 4 | +We have an array `arr` of non-negative integers. |
| 5 | + |
| 6 | +For every (contiguous) subarray `sub = [arr[i], arr[i + 1], ..., arr[j]]` (with `i <= j`), we take the bitwise OR of all the numbers in `sub`, obtaining a result `arr[i] | arr[i + 1] | ... | arr[j]`. |
| 7 | + |
| 8 | +Return the number of possible results. Results that occur more than once are only counted once in the final answer. |
| 9 | + |
| 10 | +## Examples |
| 11 | +``` |
| 12 | +Input: arr = [0] |
| 13 | +Output: 1 |
| 14 | +Explanation: There is only one possible result: 0. |
| 15 | +
|
| 16 | +Input: arr = [1,1,2] |
| 17 | +Output: 3 |
| 18 | +Explanation: The possible subarrays are [1], [1], [2], [1,1], [1,2], [1,1,2]. |
| 19 | +These yield the results 1, 1, 2, 1, 3, 3. |
| 20 | +There are 3 unique values, so the answer is 3. |
| 21 | +
|
| 22 | +Input: arr = [1,2,4] |
| 23 | +Output: 6 |
| 24 | +Explanation: The possible results are 1, 2, 3, 4, 6, and 7. |
| 25 | +``` |
| 26 | + |
| 27 | +## Approach |
| 28 | +**Key Insight**: The number of unique bitwise OR results is much smaller than the number of possible subarrays because: |
| 29 | +1. Bitwise OR is monotonic - adding more elements can only increase or keep the same value |
| 30 | +2. There are only 32 possible bits in an integer, so the number of unique results is bounded |
| 31 | + |
| 32 | +**Algorithm**: |
| 33 | +1. For each position in the array, maintain a set of all possible bitwise OR values that can be achieved by subarrays ending at that position |
| 34 | +2. For each new element, compute the bitwise OR with all previous results |
| 35 | +3. Use a HashSet to track all unique results across all positions |
| 36 | + |
| 37 | +**Why this works**: |
| 38 | +- We don't need to check all possible subarrays explicitly |
| 39 | +- We can build the results incrementally by extending subarrays from each position |
| 40 | +- The monotonicity of bitwise OR means we can efficiently track all possible values |
| 41 | + |
| 42 | +## Complexity Analysis |
| 43 | +- **Time Complexity**: O(n * 32) = O(n) - Each element can contribute at most 32 unique bitwise OR values |
| 44 | +- **Space Complexity**: O(32) = O(1) - We only need to store at most 32 unique values at any time |
| 45 | + |
| 46 | +## Key Insights |
| 47 | +- Bitwise OR is monotonic: a | b ≥ max(a, b) |
| 48 | +- The number of unique bitwise OR results is bounded by the number of bits (32 for integers) |
| 49 | +- We can efficiently track all possible results by building them incrementally |
| 50 | +- Each new element can only create new results by OR-ing with existing results |
| 51 | + |
| 52 | +## Alternative Approaches |
| 53 | +1. **Brute Force**: Check all possible subarrays - O(n²) time, but still efficient due to bounded unique results |
| 54 | +2. **Dynamic Programming**: Can be viewed as a DP problem where we track all possible OR values at each position |
| 55 | + |
| 56 | +## Solutions in Different Languages |
| 57 | + |
| 58 | +### Java |
| 59 | +```java |
| 60 | +// See solution.java |
| 61 | +class Solution { |
| 62 | + public int subarrayBitwiseORs(int[] arr) { |
| 63 | + Set<Integer> result = new HashSet<>(); |
| 64 | + Set<Integer> current = new HashSet<>(); |
| 65 | + |
| 66 | + for (int num : arr) { |
| 67 | + Set<Integer> next = new HashSet<>(); |
| 68 | + next.add(num); |
| 69 | + |
| 70 | + for (int val : current) { |
| 71 | + next.add(val | num); |
| 72 | + } |
| 73 | + |
| 74 | + result.addAll(next); |
| 75 | + current = next; |
| 76 | + } |
| 77 | + |
| 78 | + return result.size(); |
| 79 | + } |
| 80 | +} |
| 81 | +``` |
| 82 | + |
| 83 | +### JavaScript |
| 84 | +```javascript |
| 85 | +// See solution.js |
| 86 | +/** |
| 87 | + * @param {number[]} arr |
| 88 | + * @return {number} |
| 89 | + */ |
| 90 | +var subarrayBitwiseORs = function(arr) { |
| 91 | + const result = new Set(); |
| 92 | + let current = new Set(); |
| 93 | + |
| 94 | + for (const num of arr) { |
| 95 | + const next = new Set(); |
| 96 | + next.add(num); |
| 97 | + |
| 98 | + for (const val of current) { |
| 99 | + next.add(val | num); |
| 100 | + } |
| 101 | + |
| 102 | + for (const val of next) { |
| 103 | + result.add(val); |
| 104 | + } |
| 105 | + |
| 106 | + current = next; |
| 107 | + } |
| 108 | + |
| 109 | + return result.size(); |
| 110 | +}; |
| 111 | +``` |
| 112 | + |
| 113 | +## Test Cases |
| 114 | +``` |
| 115 | +Test Case 1: [0] → 1 |
| 116 | +Test Case 2: [1,1,2] → 3 |
| 117 | +Test Case 3: [1,2,4] → 6 |
| 118 | +Test Case 4: [1,2,3] → 4 |
| 119 | +Test Case 5: [1,1,1,1] → 1 |
| 120 | +``` |
| 121 | + |
| 122 | +## Edge Cases |
| 123 | +- Single element arrays |
| 124 | +- Arrays with all same elements |
| 125 | +- Arrays with large numbers |
| 126 | +- Empty arrays (though not mentioned in constraints) |
| 127 | + |
| 128 | +## Related Problems |
| 129 | +- Subarray Sum Equals K |
| 130 | +- Bitwise AND of Numbers Range |
| 131 | +- Maximum XOR of Two Numbers in an Array |
0 commit comments