Posted onEdited onInLeetCode Symbols count in article: 14kReading time ≈13 mins.
Bit/Bit_Mask好题
137. Single Number II
@kenanlv the part about XOR is often supposed to be textbook knowledge because of well-known swap implementation without tmp variable:
1 2 3
a = a^b # mix of a and b b = a^b # a^b^b = a a = a^b # a^b^a = b
If you don’t know that idea, the interviewer would probably simplify the task, asking you first to solve the problem “each element appears twice except one, find that one.” That is a very straightforward XOR usage, like in swap above
1
seen_once = seen_once^num
Once you’ll figure that out, to go to the idea of two bitmasks instead of one is not a big deal, basically it’s
NOT seen_twice AND (CHANGE see_once) NOT seen_once AND (CHANGE see_twice)
for (int num : nums) { // first appearence: // add num to seen_once // don't add to seen_twice because of presence in seen_once
// second appearance: // remove num from seen_once // add num to seen_twice
// third appearance: // don't add to seen_once because of presence in seen_twice // remove num from seen_twice seenOnce = ~seenTwice & (seenOnce ^ num); seenTwice = ~seenOnce & (seenTwice ^ num); }
return seenOnce; } }
开背!
1 2 3 4 5 6 7 8 9
publicintsingleNumber(int[] nums) { int seenOnce=0; int seenTwice=0; for (int num : nums) { seenOnce=(~seenTwice) & (seenOnce^num); seenTwice=(~seenOnce) & (seenTwice^num); } return seenOnce; }
260. Single Number III
The bitmask will have all the differences between x and y (the two singles). x has 0 and y has 1 or vice-versa in those bits. You take one difference, the rightmost one. Iterate through array again dividing into two. The ones which has 1 on the rightmost different bit into one group and those who have 0 into another group. Group1 : [x^a^a^b^b] = x Group2 : [y^c^c^d^d] = y bitmask^x = y;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
classSolution { publicint[] singleNumber(int[] nums) { // difference between two numbers (x and y) which were seen only once intbitmask=0; for (int num : nums) bitmask ^= num;
// rightmost 1-bit diff between x and y intdiff= bitmask & (-bitmask);
intx=0; // bitmask which will contain only x for (int num : nums) if ((num & diff) != 0) x ^= num;
returnnewint[]{x, bitmask^x}; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
publicint[] singleNumber(int[] nums) { int ab=0; for (int num : nums) { ab^=num; } //ab=a^b int r=ab&(-ab); int a=0; for (int num : nums) { if((num&r)!=0){ a^=num; } } returnnewint[]{a,ab^a}; }
191. Number of 1 Bits
1 2 3 4 5 6 7 8 9
publicinthammingWeight(int n) { int count=0; while(n!=0){ count+=n&1; //must use logical shift, not arithmetic shift n>>>=1; //n>>=1则不行 } return count; }
338. Counting Bits
Follow up:
It is very easy to come up with a solution with a runtime of O(n log n). Can you do it in linear time O(n) and possibly in a single pass?
publicintminFlips(int a, int b, int c) { String s1=convert(a); String s2=convert(b); String s3=convert(c); int res=0; for (inti=0; i < 32; i++) { int c1=s1.charAt(i)-'0'; int c2=s2.charAt(i)-'0'; int c3=s3.charAt(i)-'0'; int or=c1|c2; if(or==c3){//0 0, 1 1 continue; } if(or==0 && c3==1){//0 1 res++; }elseif(c1==1 && c2==1){ res+=2; }else{ res++; } } return res; }
publiclongmaximumOr(int[] nums, int k) { long res=0; long base=0; long backup=0; //at least 2 occurrences for each 1 bit for (int num : nums) { backup|=base# base|=num; } //long: 10^19, no overflow for (int num : nums) { res=Math.max(res,(base^num)|backup|(long)num<<k); } return res; }
2741. Special Permutations
dp + bit mask: using bit masks to present dp states
privateintdfs(int[] arr, int n, int cur){ while(cur<n && arr[cur]==0){ cur++; } if(cur==n){ return0; } int asset=arr[cur]; int res=Integer.MAX_VALUE; for(int i=cur+1; i<n; i++){ //0 or same sign, no transaction make sense if(arr[i]*asset>=0){ continue; } //else, try to resolve cur by i arr[i]+=asset; //[0,cur] is all resolved (==0) res=Math.min(res,1+dfs(arr,n,cur+1)); arr[i]-=asset; } return res; }
DP with bitmask
思路:
n non-zero balance, each settles with ACH, needs at most n transactions
Let one of the people at act as Clearing House, other n-1 settles via him with n-1 transactions. Since the total sum is 0, settling other n-1 with automatically settle this Clearing House guy as well. needs at most n-1 transactions
if we find 2 zero-balance subgroups, one of size k and other n-k
instead of n-1 transactions with a same Clearing guy
make k-1 transactions within first group choosing a Clearing House guy, and n-k-1 transactions within second group choosing another Clearing House guy
int[] dp; int n; publicintminTransfers(int[][] transactions) { Map<Integer,Integer> map=newHashMap<>(); for (int[] arr : transactions) { map.put(arr[0],map.getOrDefault(arr[0],0)+arr[2]); map.put(arr[1],map.getOrDefault(arr[1],0)-arr[2]); } List<Integer> list=newArrayList<>(); for (Integer key : map.keySet()) { if(map.get(key)!=0){ list.add(map.get(key)); } } //debt: 3 means needing to give 3, // -3 means needing to receive 3 int[] arr=list.stream().mapToInt(i->i).toArray(); n=arr.length; dp=newint[1<<n]; //[1,1<<n -1] Arrays.fill(dp,-1); dp[0]=0; //注意:bit operation优先级低,一定要加括号 return n-dfs(arr,(1<<n)-1); }
privateintdfs(int[] arr, int mask){ //maximum number of sub groups that sum = 0 //normally need n-1 transactions to settle a group //but if we find m subgroups of balance 0, //we only nned n-m transactions if(dp[mask]!=-1){ return dp[mask]; } int total=0; int max=0; for (inti=0; i < n; i++) { int cur=1<<i; if((mask&cur)!=0){ max=Math.max(max,dfs(arr,mask^cur)); total+=arr[i]; } } dp[mask]=max + (total==0 ? 1 : 0); return dp[mask]; }