LeetCode - Easy - 190. Reverse Bits

Topic

  • Bit Manipulation
  • Two Pointers

Description

https://leetcode.com/problems/reverse-bits/

Reverse bits of a given 32 bits unsigned integer.

Note:

  • Note that in some languages such as Java, there is no unsigned integer type. In this case, both input and output will be given as a signed integer type. They should not affect your implementation, as the integer’s internal binary representation is the same, whether it is signed or unsigned.
  • In Java, the compiler represents the signed integers using 2’s complement notation. Therefore, in Example 2 above, the input represents the signed integer -3 and the output represents the signed integer -1073741825.

Follow up:

If this function is called many times, how would you optimize it?

Example 1:

Input: n = 00000010100101000001111010011100
Output:    964176192 (00111001011110000010100101000000)
Explanation: The input binary string 00000010100101000001111010011100 represents the unsigned integer 43261596, so return 964176192 which its binary representation is 00111001011110000010100101000000.

Example 2:

Input: n = 11111111111111111111111111111101
Output:   3221225471 (10111111111111111111111111111111)
Explanation: The input binary string 11111111111111111111111111111101 represents the unsigned integer 4294967293, so return 3221225471 which its binary representation is 10111111111111111111111111111111.

Constraints:

  • The input must be a binary string of length 32

Analysis

方法一:双指针 + 位操作(我写的)

PS:

在二进制中,设置特定的数位:

  • 设置特定的数位为1,其他数位保持不变,用到 | 位运算符。如,设置01101的左边第1位为1,则01101 | 10000 = 11101
  • 设置特定的数位为0,其他数位保持不变,用到 ~、& 位运算符。如,设置11101的左边第1位为0,11101 & (~10000) = 11101 & 01111 = 01101

方法二:位操作(乾坤大挪移)

for 8 bit binary number abcdefgh, the process is as follow:

abcdefgh -> efghabcd -> ghefcdab -> hgfedcba


方法三:类似队列 + 位操作

We first intitialize result to 0. We then iterate from 0 to 31 (an integer has 32 bits). In each iteration:

We first shift result to the left by 1 bit. Then, if the last digit of input n is 1, we add 1 to result. To find the last digit of n, we just do: (n & 1).

Example, if n=5 (101), n&1 = 101 & 001 = 001 = 1;however, if n = 2 (10), n&1 = 10 & 01 = 00 = 0).

Finally, we update n by shifting it to the right by 1 (n >>= 1). This is because the last digit is already taken care of, so we need to drop it by shifting n to the right by 1.

At the end of the iteration, we return result.

Example, if input n = 13 (represented in binary as 0000,0000,0000,0000,0000,0000,0000,1101, the “,” is for readability),
calling reverseBits(13) should return:
1011,0000,0000,0000,0000,0000,0000,0000

Here is how our algorithm would work for input n = 13:

Initially, result = 0 = 0000,0000,0000,0000,0000,0000,0000,0000,
n = 13 = 0000,0000,0000,0000,0000,0000,0000,1101

Starting for loop:

i = 0:

result = result << 1 = 0000,0000,0000,0000,0000,0000,0000,0000.
n&1 = 0000,0000,0000,0000,0000,0000,0000,1101
& 0000,0000,0000,0000,0000,0000,0000,0001
= 0000,0000,0000,0000,0000,0000,0000,0001 = 1
therefore result = result + 1 =
0000,0000,0000,0000,0000,0000,0000,0000 + 0000,0000,0000,0000,0000,0000,0000,0001
= 0000,0000,0000,0000,0000,0000,0000,0001 = 1

Next, we right shift n by 1 (n >>= 1) (i.e. we drop the least significant bit) to get:
n = 0000,0000,0000,0000,0000,0000,0000,0110.
We then go to the next iteration.

i = 1:

result = result << 1 = 0000,0000,0000,0000,0000,0000,0000,0010;
n&1 = 0000,0000,0000,0000,0000,0000,0000,0110 &
0000,0000,0000,0000,0000,0000,0000,0001
= 0000,0000,0000,0000,0000,0000,0000,0000 = 0;
therefore we don’t increment result.
We right shift n by 1 (n >>= 1) to get:
n = 0000,0000,0000,0000,0000,0000,0000,0011.
We then go to the next iteration.

i = 2:

result = result << 1 = 0000,0000,0000,0000,0000,0000,0000,0100.
n&1 = 0000,0000,0000,0000,0000,0000,0000,0011 &
0000,0000,0000,0000,0000,0000,0000,0001 =
0000,0000,0000,0000,0000,0000,0000,0001 = 1
therefore result = result + 1 =
0000,0000,0000,0000,0000,0000,0000,0100 +
0000,0000,0000,0000,0000,0000,0000,0001 =
result = 0000,0000,0000,0000,0000,0000,0000,0101
We right shift n by 1 to get:
n = 0000,0000,0000,0000,0000,0000,0000,0001.
We then go to the next iteration.

i = 3:

result = result << 1 = 0000,0000,0000,0000,0000,0000,0000,1010.
n&1 = 0000,0000,0000,0000,0000,0000,0000,0001 &
0000,0000,0000,0000,0000,0000,0000,0001 =
0000,0000,0000,0000,0000,0000,0000,0001 = 1
therefore result = result + 1 =
= 0000,0000,0000,0000,0000,0000,0000,1011
We right shift n by 1 to get:
n = 0000,0000,0000,0000,0000,0000,0000,0000 = 0.

Now, from here to the end of the iteration, n is 0, so (n&1)
will always be 0 and and n >>=1 will not change n. The only change
will be for result <<=1, i.e. shifting result to the left by 1 digit.
Since there we have i=4 to i = 31 iterations left, this will result
in padding 28 0’s to the right of result. i.e at the end, we get
result = 1011,0000,0000,0000,0000,0000,0000,0000

This is exactly what we expected to get.


方法四:比方法三精简些

Submission

public class ReverseBits {

	// 方法一:双指针 + 位操作
	public int reverseBits1(int n) {
		int p1 = Integer.MIN_VALUE, p2 = 1;
		do {
			boolean b1 = (n & p1) == 0;
			boolean b2 = (n & p2) == 0;
			if (b1 ^ b2) {
				n = b1 ? (n | p1) : (n & ~p1);
				n = b2 ? (n | p2) : (n & ~p2);
			}
			p1 >>>= 1;
			p2 <<= 1;
		} while (p1 > p2);

		return n;
	}

	// 方法二:乾坤大挪移
	public int reverseBits2(int n) {
		n = (n >>> 16) | (n << 16);
		n = ((n & 0xff00ff00) >>> 8) | ((n & 0x00ff00ff) << 8);
		n = ((n & 0xf0f0f0f0) >>> 4) | ((n & 0x0f0f0f0f) << 4);
		n = ((n & 0xcccccccc) >>> 2) | ((n & 0x33333333) << 2);
		n = ((n & 0xaaaaaaaa) >>> 1) | ((n & 0x55555555) << 1);
		return n;
	}

	// 方法三:队列 + 位操作
	public int reverseBits3(int n) {
		if (n == 0)
			return 0;

		int result = 0;
		for (int i = 0; i < 32; i++) {
			result <<= 1;
			if ((n & 1) == 1)
				result++;// 可写成 result += n&1;
			n >>= 1;
		}
		return result;
	}

	// 方法四:比方法三精简些
	public int reverseBits4(int n) {
		int result = 0;
		for (int i = 0; i < 32; i++)
			result = (result << 1) + (n >> i & 1);
		return result;
	}

}

Test

import static org.junit.Assert.*;
import org.junit.Test;

public class ReverseBitsTest {

	@Test
	public void test() {
		ReverseBits obj = new ReverseBits();
		
		assertEquals(Integer.parseInt("00000000000000001111111111111110", 2), //
				obj.reverseBits1(Integer.parseInt("01111111111111110000000000000000", 2)));
		assertEquals(964176192, obj.reverseBits1(Integer.parseInt("00000010100101000001111010011100", 2)));
		assertEquals(-1073741825, obj.reverseBits1(-3));
		
		assertEquals(Integer.parseInt("00000000000000001111111111111110", 2), //
				obj.reverseBits2(Integer.parseInt("01111111111111110000000000000000", 2)));
		assertEquals(964176192, obj.reverseBits2(Integer.parseInt("00000010100101000001111010011100", 2)));
		assertEquals(-1073741825, obj.reverseBits2(-3));

		assertEquals(Integer.parseInt("00000000000000001111111111111110", 2), //
				obj.reverseBits3(Integer.parseInt("01111111111111110000000000000000", 2)));
		assertEquals(964176192, obj.reverseBits3(Integer.parseInt("00000010100101000001111010011100", 2)));
		assertEquals(-1073741825, obj.reverseBits3(-3));
		
		assertEquals(Integer.parseInt("00000000000000001111111111111110", 2), //
				obj.reverseBits4(Integer.parseInt("01111111111111110000000000000000", 2)));
		assertEquals(964176192, obj.reverseBits4(Integer.parseInt("00000010100101000001111010011100", 2)));
		assertEquals(-1073741825, obj.reverseBits4(-3));
		
	}
}

你可能感兴趣的:(LeetCode,leetcode,位操作,two,pointers)