Jc-alt logo
jc
data structures and algorithms

LeetCode: Bit Manipulation

LeetCode: Bit Manipulation
15 min read
#data structures and algorithms
Table Of Contents

Bit Manipulation Intro

What is Bit Manipulation

bits!

Bit Manipulation IRL

bits!

Bit Manipulation Application: Bit Manipulation

Pattern: bits!

Ex: bits numbers!!

    def bitss!(n: int) -> int:

        return n+1

136. Single Number ::1:: - Easy

Topics: Array, Bit Manipulation

Intro

Given a non-empty array of integers nums, every element appears twice except for one. Find that single one. You must implement a solution with a linear runtime complexity and use only constant extra space.

Example InputOutput
nums = [2,2,1]1
nums = [4,1,2,1,2]4
nums = [1]1

Constraints:

1 ≤ nums.length ≤ 3 * 104

-3 * 104 ≤ nums[i] ≤ 3 * 104

Each element in the array appears twice except for one element which appears only once.

Abstraction

Given a list of integers, find the integer that only appears once.

Space & Time Complexity

SolutionTime ComplexitySpace ComplexityTime RemarkSpace Remark
BugError

Brute Force:

AspectTime ComplexitySpace ComplexityTime RemarksSpace Remarks

Find the Bug:

Solution 1: Bit Manipulation XOR Trick - Bit Manipulation/Bit Manipulation

    def singleNumber(self, nums: List[int]) -> int:
        
        # Note:
        # 1. num XOR num -> 0
        # 2. num XOR 0 -> num
        # 3. XOR is commutative and associative
        # 4. Iterate XOR over all pairs of numbers to leave the unique number

        result = 0

        # Accumulative XOR to generate the unique number
        for num in nums:
            result ^= num

        # overall: time complexity O(n)
        # overall: space complexity O(1)
        return result

191. Number of 1 Bits ::2:: - Easy

Topics: Divide and Conquer, Bit Manipulation

Intro

Given a positive integer n, write a function that returns the number of set bits in its binary representation (also known as the Hamming weight). A set bit refers to a bit in the binary representation of a number that has a value of 1. Follow up: If this function is called many times, how would you optimize it?

Example InputOutput
n = 113
n = 1281
n = 214748364530

Constraints:

1 ≤ n ≤ 231 - 1

Abstraction

Given an integer, return how many bits are set to 1 in its binary representation.

Space & Time Complexity

SolutionTime ComplexitySpace ComplexityTime RemarkSpace Remark
BugError

Brute Force:

AspectTime ComplexitySpace ComplexityTime RemarksSpace Remarks

Find the Bug:

Solution 1: Basic Shift and Mask - Bit Manipulation/Bit Manipulation

    def hammingWeight(self, n: int) -> int:
        
        # Note:
        # 1. Given a 32-bit signed integer, check all bits for set
        # 2. Set bit check -> check lowest bit
        # 3. Iterate -> shift binary representation by 1
        # Result -> count of set bits of binary representation

        count = 0

        for _ in range(32):
            
            # set bit check -> validate if lowest bit is 1
            count += n & 1 

            # iterate -> shift right by 1 regardless
            n >>= 1

        # overall: time complexity O(32) = O(1)
        # overall: space complexity O(1)
        return count

Solution 2: Brian Kernighan Algorithm - Bit Manipulation/Bit Manipulation

    def hammingWeight(self, n: int) -> int:
        
        # Note:
        # 1. Iterate while some bit is set
        # 2. Removes the lowest/rightmost set bit
        # 3. Add to count
        # Result -> count number of set bits

        count = 0

        # continues while some bit is set
        while n:
            
            # clears the right most 1 and everything to the right of it
            # n      = 101000
            # n - 1  = 100111
            # ----------------
            # n&(n-1)= 100000

            n &= (n - 1)

            # add to set bit count
            count += 1

        # overall: time complexity O(k), k = number of set bits
        # overall: space complexity O(1)
        return count

338. Counting Bits ::2:: - Easy

Topics: Dynamic Programming, Bit Manipulation

Intro

Given an integer n, return an array ans of length n + 1 such that for each i (0 < = i < = n), ans[i] is the number of 1's in the binary representation of i.

Example InputOutput
n = 2[0,1,1]
n = 5[0,1,1,2,1,2]

Constraints:

0 ≤ n ≤ 105

Abstraction

Given an integer, return an array representing 0 -> n, where each index is the number of set bits for that integer.

Space & Time Complexity

SolutionTime ComplexitySpace ComplexityTime RemarkSpace Remark
BugError

Brute Force:

AspectTime ComplexitySpace ComplexityTime RemarksSpace Remarks

Find the Bug:

Solution 1: DP with Integer Division + Bit Shift - Bit Manipulation/Bit Manipulation

    def countBits(self, n: int) -> List[int]:
        
        # Note:
        # 1. DP relation via bit manipulation
        #    i >> 1 removes the least significant bit
        #    i & 1 checks if least significant bit is set
        # 2. Recurrence:
        #    dp[i] = dp[i >> 1] + (i & 1)
        # 3. Build array bottom-up from 0 to n

        ans = [0] * (n + 1)

        for i in range(1, n + 1):
            ans[i] = ans[i >> 1] + (i & 1)

        # overall: time complexity O(n)
        # overall: space complexity O(n)
        return ans

190. Reverse Bits ::1:: - Easy

Topics: Divide and Conquer, Bit Manipulation

Intro

Reverse bits of a given 32 bits signed integer. Follow up: If this function is called many times, how would you optimize it?

Example InputOutput
n = 43261596964176192
n = 21474836441073741822

Constraints:

0 ≤ n ≤ 231 - 2

n is even

Abstraction

Reverse bits of a 32 signed integer.

Space & Time Complexity

SolutionTime ComplexitySpace ComplexityTime RemarkSpace Remark
BugError

Brute Force:

AspectTime ComplexitySpace ComplexityTime RemarksSpace Remarks

Find the Bug:

Solution 1: Iterative Bit Manipulation - Bit Manipulation/Bit Manipulation

    def reverseBits(self, n: int) -> int:

        # Note:
        # 1. Given a 32-bit signed integer
        # 2. Iterate res left by 1 and n right by 1 to continuing copying right most bit
        # Result -> reversed n

        result = 0

        # Iterate over 32 bits
        for _ in range(32):

            # shift result left by 1, making space for new rightmost bit
            result <<= 1

            # copy n's rightmost bit (least significant) to res
            result |= n & 1
            
            # shift n right by 1, preparing next bit for copy
            n >>= 1
        
        # overall: time complexity O(n)
        # overall: space complexity O(n)
        return result

268. Missing Number ::2:: - Easy

Topics: Array, Hash Table, Math, Binary Search, Bit Manipulation, Sorting

Intro

Given an array nums containing n distinct numbers in the range [0, n], return the only number in the range that is missing from the array. Follow up: Could you implement a solution using only O(1) extra space complexity and O(n) runtime complexity?

Example InputOutput
nums = [3,0,1]2
nums = [0,1]2
nums = [9,6,4,2,3,5,7,0,1]8

Constraints:

n == nums.length

1 ≤ n ≤ 104

0 ≤ nums[i] ≤ n

All the numbers of nums are unique.

Abstraction

Given an array of n distinct numbers, in range [0, n], return the only number that is missing from the range.

Space & Time Complexity

SolutionTime ComplexitySpace ComplexityTime RemarkSpace Remark
BugError

Brute Force:

AspectTime ComplexitySpace ComplexityTime RemarksSpace Remarks

Find the Bug:

Solution 1: Verify Against Math Formula - Bit Manipulation/Bit Manipulation

    def missingNumber(self, nums: List[int]) -> int:
        
        # Note:
        # Math approach
        # 0. The sum of numbers 0 -> n is (n * (n+1)/2)
        # 1. Sum all elements in nums
        # 2. Missing = expected sum - actual sum

        n = len(nums)
        
        expected_sum = n * (n + 1) // 2
        
        sum = 0
        for n in nums:
            sum += n

        missing = expected_sum - sum

        # overall: time complexity O(n)
        # overall: space complexity O(1)
        return missing

Solution 2: XOR Trick - Bit Manipulation/Bit Manipulation

    def missingNumber(self, nums: List[int]) -> int:
        
        # Note:
        # XOR approach
        # 1. num XOR num -> 0, all paired numbers cancel out
        # 2. Iterate over range -> num XOR index -> 0
        # 3. Missing number -> will not XOR correctly, will remain at end
        # Result -> missing number

        n = len(nums)

        missing = 0

        # loop from 0 to n inclusive
        for i in range(n + 1):

            # XOR index and array value
            if i < n:
                missing ^= i ^ nums[i]

            # i == n, just XOR the number n, avoid out of bounds index
            else:
                missing ^= i

        # Time Complexity: O(n)
        # Space Complexity: O(1)
        return missing

371. Sum of Two Integers ::1:: - Medium

Topics: Math, Bit Manipulation

Intro

Given two integers a and b, return the sum of the two integers without using the operators + and -.

Example InputOutput
a = 1, b = 23
a = 2, b = 35

Constraints:

Abstraction

Given two integers, return the sum without using operators.

Space & Time Complexity

SolutionTime ComplexitySpace ComplexityTime RemarkSpace Remark
BugError

Brute Force:

AspectTime ComplexitySpace ComplexityTime RemarksSpace Remarks

Find the Bug:

Solution 1: Bit Manipulation - Bit Manipulation/Bit Manipulation

    def getSum(self, a: int, b: int) -> int:
        
        # -----------------------------------------
        # a  b  '^' sum (without carry)  carry
        # 0  0        0                    0
        # 0  1        1                    0
        # 1  0        1                    0
        # 1  1        0                    1

        # -----------------------------------------
        # Note:
        # all bits are processed in parallel, one bit at a time

        # Iteration 1: sum bits 0 and 1 (rightmost two bits) 
        # a = 0110
        # b = 0011
        # sum_ = a ^ b = 0101
        # carry = (a & b) << 1 = 0100  (carry from bit 1 moves to bit 2)

        # Iteration 2: sum bits 2 and 2 (carry affecting bit 2)
        # a = sum_ = 0101
        # b = carry = 0100
        # sum_ = a ^ b = 0001
        # carry = (a & b) << 1 = 0100 << 1 = 1000  (carry from bit 2 moves to bit 3)

        # Iteration 3: sum bits 3 and 3 (carry affecting highest bit)
        # a = 0001
        # b = 1000
        # sum_ = 1001
        # carry = (a & b) << 1 = 0000  (no more carry)

        # Done, carry is 0 → final sum = 1001 (9)

        # -----------------------------------------

        # Note:
        # 1. (a ^ b) -> acts as sum without carry, mask ensures all operations are restricted to 32 bits
        # 2. (a & b) << 1 -> Carry is 1 only when both bits are 1, otherwise 0
        # 2. carry -> Use AND (&) + left shift (<<)
        # 3. Repeat until carry is 0 -> no value left
        # 4. Handle negative numbers with 32-bit mask
        # Result ->

        # limit to 32 bits
        MASK = 0xFFFFFFFF
        maxInt = 2**31 - 1

        # while carry is not 0
        while b != 0:

            # sum without carry
            sum_ = (a ^ b) & MASK

            # carry
            carry = ((a & b) << 1) & MASK
            
            # update a and b
            a, b = sum_, carry

        # if a > 2^31-1, it's negative in 32-bit signed
        res = a if a <= maxInt else ~(a ^ MASK)

        # overall: time complexity O(1)
        # overall: space complexity O(1)
        return res

7. Reverse Integer ::1:: - Medium

Topics: Math

Intro

Given a signed 32-bit integer x, return x with its digits reversed. If reversing x causes the value to go outside the signed 32-bit integer range [-2^31, 2^31 - 1], then return 0. Assume the environment does not allow you to store 64-bit integers (signed or unsigned).

Example InputOutput
x = 123321
x = -123-321
x = 12021

Constraints:

-231 ≤ x ≤ 231 - 1

Abstraction

Given a 32-bit integer, reverse it.

Space & Time Complexity

SolutionTime ComplexitySpace ComplexityTime RemarkSpace Remark
BugError

Brute Force:

AspectTime ComplexitySpace ComplexityTime RemarksSpace Remarks

Find the Bug:

Solution 1: Iterative Math Approach - Bit Manipulation/Bit Manipulation

    def reverse(self, x: int) -> int:
        
        # -----------------------------------------
        # Iterative process: process each digit from right to left

        # Example: x = 123
        # Iteration 1:
        #   digit = 123 % 10 = 3
        #   x = 123 // 10 = 12
        #   res = 0 * 10 + 3 = 3
        #
        # Iteration 2:
        #   digit = 12 % 10 = 2
        #   x = 12 // 10 = 1
        #   res = 3 * 10 + 2 = 32
        #
        # Iteration 3:
        #   digit = 1 % 10 = 1
        #   x = 1 // 10 = 0
        #   res = 32 * 10 + 1 = 321
        #
        # Done, x == 0 → final reversed number = 321

        # -----------------------------------------
        # Note:
        # 1. Extract digits one by one using modulo 10
        # 2. Append to result using multiply by 10 + digit
        # 3. Handle negative numbers
        # 4. Check for 32-bit overflow
        # Result -> 


        INT_MAX = 2**31 - 1 # 2147483647
        INT_MIN = -2**31    # -2147483648

        res = 0
        sign = 1 if x >= 0 else -1
        x = abs(x)

        while x != 0:
            digit = x % 10
            x //= 10

            # Check overflow before multiplying by 10
            if res > (INT_MAX - digit) // 10:
            
                # would overflow 32-bit signed integer
                return 0

            res = res * 10 + digit

        # Apply original sign
        res1 = sign * res

        # overall: time complexity O(log10(x))
        # overall: space complexity O(1)
        return res1