Bit Manipulation · 7 of 10
Copy set bits in a range
Look through a window over the bits of N, and switch on the same bits in M wherever N has a 1.
- Simple way
- time O(R - L + 1)
room O(1) - Clever way
- time O(1)
room O(1)
The problem, simply
You get two numbers, M and N, and a window of positions from L to R. Positions are counted from 1, starting at the rightmost bit.
For every position inside the window where N has a 1, make that bit of M a 1 too. Never turn a bit of M off, and never touch bits outside the window. Give back the new M.
A story to remember it
Picture it
M = 43 and N = 59. The window is positions 2 to 5, which are bits 1 to 4 in the drawing because the drawing counts from 0. Inside the window N has 1s at bits 1, 3 and 4.
- path
Examples
A normal case
- In
M = 10, N = 13, L = 2, R = 3- Out
14
M is 1010 and N is 1101. In positions 2 and 3, N has a 0 and then a 1. So position 3 of M turns on: 1110 = 14.
Small window at the right end
- In
M = 8, N = 7, L = 1, R = 2- Out
11
N has 1s at positions 1 and 2. M was 1000, so it becomes 1011 = 11. The 1 at position 3 of N is outside the window and is ignored.
Some bits are already on
- In
M = 43, N = 59, L = 2, R = 5- Out
59
N has 1s at positions 2, 4 and 5. M already has positions 2 and 4 on, so only position 5 is new. M goes from 101011 to 111011 = 59.
Nothing to copy
- In
M = 5, N = 8, L = 1, R = 3- Out
5
N is 1000. Its only 1 is at position 4, outside the window. M stays 5.
The whole number
- In
M = 0, N = -1, L = 1, R = 32- Out
-1
The window covers all 32 bits, so M becomes a copy of N's 1s, which is all 32 bits on. A careless mask gets this wrong (see below).
Way 1: the simple way
Walk through the window one position at a time.
- For each position
ifromLtoR, make a one bit numberbit = 1 << (i - 1). - If
N & bitis not 0,Nhas a 1 there, so doM = M | bit. - Give back
M.
class Solution {
public static int copySetBits(int m, int n, int l, int r) {
for (int i = l; i <= r; i++) {
int bit = 1 << (i - 1); // positions start at 1, shifts start at 0
if ((n & bit) != 0) {
m |= bit; // switch on the same light in M
}
}
return m;
}
}How long it takes: one step per position in the window, O(R - L + 1), which is at most 32 steps. Extra room: O(1).
Way 2: the clever way
Make the cardboard first: a number called a mask, with 1s exactly on positions L to R and 0s everywhere else. Then two bit operations finish the job.
(1 << R) - 1has 1s on positions 1 toR. Taking 1 away from a lone 1 bit turns on every bit below it.(1 << (L - 1)) - 1has 1s on positions 1 toL - 1, the part we must cut away.- XOR the two to keep only positions
LtoR. That is the mask. N & maskkeeps only the 1s ofNthat show through the hole.M | (N & mask)switches those on inMand leaves every other bit alone.
Cut the stencil, then copy through it
01 / 07
M = 43 and N = 59. The window is positions 2 to 5, counting from 1 on the right. In the drawing, bits are counted from 0, so that is bits 1 to 4.
- checking
- done
- answer
- rejected
- path
- just added
- ignored
class Solution {
public static int copySetBits(int m, int n, int l, int r) {
long upTo = (1L << r) - 1; // ones on positions 1 to r
long below = (1L << (l - 1)) - 1; // ones on positions 1 to l - 1
long mask = upTo ^ below; // ones on positions l to r only
return (int) (m | (n & mask)); // copy N's ones through the hole
}
}How long it takes: a fixed handful of bit operations, O(1). Extra room: one mask, O(1).
Watch out for
- Off by one. Positions in this problem start at 1, but shifts start at 0. Position
iis1 << (i - 1). - Using
^or=instead of|when copying. The problem says only switch on. XOR would switch off the bits that are on in both. - Forgetting the cut.
(1 << R) - 1alone also copies positions belowL.
What interviewers ask next
- Copy the window exactly, zeros too? Clear the window in
Mfirst, then OR:(M & ~mask) | (N & mask). This is how you write a field into a packed number. - Toggle all bits of
Min the range?M ^ mask. - Clear all bits of
Min the range?M & ~mask. - Another way to build the mask?
((1L << (R - L + 1)) - 1) << (L - 1): a run ofR - L + 1ones, slid up to positionL. - Check whether all bits in the range are on in
N?(N & mask) == mask.
Remember this
Grown-up words: the cardboard with the hole is a bit mask, looking through it is bitwise AND, switching lights on is bitwise OR, and cutting away the lower part is XOR of two masks.