[LeetCode 982] Triples with Bitwise AND Equal To Zero
Given an array of integers A
, find the number of triples of indices (i, j, k) such that:
0 <= i < A.length
0 <= j < A.length
0 <= k < A.length
A[i] & A[j] & A[k] == 0
, where&
represents the bitwise-AND operator.
Example 1:
Input: [2,1,3]
Output: 12
Explanation: We could choose the following i, j, k triples:
(i=0, j=0, k=1) : 2 & 2 & 1
(i=0, j=1, k=0) : 2 & 1 & 2
(i=0, j=1, k=1) : 2 & 1 & 1
(i=0, j=1, k=2) : 2 & 1 & 3
(i=0, j=2, k=1) : 2 & 3 & 1
(i=1, j=0, k=0) : 1 & 2 & 2
(i=1, j=0, k=1) : 1 & 2 & 1
(i=1, j=0, k=2) : 1 & 2 & 3
(i=1, j=1, k=0) : 1 & 1 & 2
(i=1, j=2, k=0) : 1 & 3 & 2
(i=2, j=0, k=1) : 3 & 2 & 1
(i=2, j=1, k=0) : 3 & 1 & 2
Note:
1 <= A.length <= 1000
0 <= A[i] < 2^16
Solution that you came up: there are 3 cases: 1. all 3 indices are the same; 2. 2 indices are the same; 3. all 3 indices are different.
case 1: count how many 0s;
case 2: has pattern(x, x, y), fix x then find y such that A[x] & A[y] is 0, there are 3 positions that we can put y into.
case 3: dp[i] is the number of pairs(x != y) so far such that (A[x] & A[y]) == i. Loop through A and fix the 3rd position index of a triple, then check all possible pairs' & value to see if we can get a valid triple. If we can, add 3! (Order matters). After considering all possible triples that end at the current index, update dp[] using the current number as the 2nd index.
Runtime is O(N * N + N * 2^16), space is O(2^16).
class Solution { public int countTriplets(int[] A) { int ans = 0; //(0,0,0) for(int v : A) { if(v == 0) { ans++; } } //(x,x,y),(x,y,x),(y,x,x) for(int i = 0; i < A.length; i++) { for(int j = 0; j < A.length; j++) { if(j == i) { continue; } if((A[i] & A[j]) == 0) { ans += 3; } } } //(x,y,z) and all its permutations //dp[i]: the number of pairs(x != y) so far such that (A[x] & A[y]) == i if(A.length >= 3) { int n = 1 << 16; int[] dp = new int[n]; dp[A[0] & A[1]]++; for(int k = 2; k < A.length; k++) { for(int v = 0; v < n; v++) { if((v & A[k]) == 0) { ans += dp[v] * 6; } } for(int i = 0; i < k; i++) { dp[A[i] & A[k]]++; } } } return ans; } }
A more concise solution
Instead of computing 3 separate cases, we can just define dp[i] as the number of index pairs (x, y) such that (A[x] & A[y]) == i. Then loop through all possible pairs including same index to update dp. Then we loop through A to fill in a 3rd index to make triples. Since each index is unique, we'll not have double counting. For each index, loop through all pairs' & value to check if we can make a valid triple, update final count. Both the runtime and space complexity are the same with the above solution.
class Solution { public int countTriplets(int[] A) { int ans = 0; int[] dp = new int[1 << 16]; for(int i = 0; i < A.length; i++){ for(int j = 0; j < A.length; j++){ int v = A[i] & A[j]; dp[v]++; } } for(int i = 0; i < A.length; i++){ for(int j = 0; j < dp.length; j++) { if((A[i] & j) == 0){ //use i as the 3rd index ans += dp[j]; } } } return ans; } }