LeetCode: Bit Manipulation

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+1136. 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 Input | Output |
|---|---|
| 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
| Solution | Time Complexity | Space Complexity | Time Remark | Space Remark |
|---|---|---|---|---|
| Bug | Error |
|---|---|
Brute Force:
| Aspect | Time Complexity | Space Complexity | Time Remarks | Space Remarks |
|---|---|---|---|---|
Find the Bug:
Solution 1: [XOR] Duplicate Cancellation Single Identity Trick - Bit Manipulation/Bit Manipulation
def singleNumber(self, nums: List[int]) -> int:
# XOR Cancellation:
# Every number appears twice except one, return the single number
# Idea:
# XOR cancels duplicate numbers
# XOR Properties:
# 1. a ^ a = 0 (duplicates cancel)
# 2. a ^ 0 = a (identity)
# 3. XOR is commutative and associative
# Running Product
result = 0
# tc: iterate over n O(n)
for num in nums:
# XOR over all numbers, duplicates are remove, single remains
# tc: O(1)
result ^= num
# overall: tc O(n)
# overall: sc O(1)
return result191. 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 Input | Output |
|---|---|
| n = 11 | 3 |
| n = 128 | 1 |
| n = 2147483645 | 30 |
Constraints:
1 ≤ n ≤ 231 - 1
Abstraction
Given an integer, return how many bits are set to 1 in its binary representation.
Space & Time Complexity
| Solution | Time Complexity | Space Complexity | Time Remark | Space Remark |
|---|---|---|---|---|
| Bug | Error |
|---|---|
Brute Force:
| Aspect | Time Complexity | Space Complexity | Time Remarks | Space Remarks |
|---|---|---|---|---|
Find the Bug:
Solution 1: [(>>) Shift and (& 1) Mask ] Shift All Bits By 1 And Bit Mast Rightmost - Bit Manipulation/Bit Manipulation
def hammingWeight(self, n: int) -> int:
# Basic Shift + Mask:
# Count number of set bits (1s) in binary representation
# Idea:
# - Check lowest bit using AND mask
# - Shift bits right to process next position
# Bit Properties:
# 1. n & 1 = returns rightmost bit (1 if set, 0 if not)
# 2. n >> 1 = shift all bits right by one position
# Running Count:
# stores total number of set bits found so far
# sc: O(1)
count = 0
# tc: iterate over 32 bits (problem constraint) O(1)
for _ in range(32):
# Grab rightmost bit, add to running count
# 1 if set, 0 is not
# tc: O(1)
count += n & 1
# Shift all bits right by one position, to process next bit
# tc: O(1)
n >>= 1
# overall: tc O(32) ~= O(1)
# overall: sc O(1)
return countSolution 2: [Brian Kernighan] Brian Kernighan Algorithm [TC Opt] - Bit Manipulation/Bit Manipulation
def hammingWeight(self, n: int) -> int:
# Brian Kernighan Algorithm
# Count number of set bits efficiently
# Idea:
# Each operation removes ONE set bit
# Trick:
# n & (n - 1) clears the rightmost set bit
# n = 101000
# n - 1 = 101111 &
# -----------------
# res = 100000
# Running Count:
# counts how many set bits have been removed
# sc: O(1)
count = 0
# Continues while any bit is set
# Runs only k times (k = number of set bits)
# tc: O(k)
while n:
# Remove the lowest (rightmost) set bit
n &= (n - 1)
# Increment count for removed bit
count += 1
# overall: tc O(k) =~ O(1)
# overall: sc O(1)
return count338. 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 Input | Output |
|---|---|
| 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
| Solution | Time Complexity | Space Complexity | Time Remark | Space Remark |
|---|---|---|---|---|
| Bug | Error |
|---|---|
Brute Force:
| Aspect | Time Complexity | Space Complexity | Time Remarks | Space Remarks |
|---|---|---|---|---|
Find the Bug:
Solution 1: [5 (101) == 2 (10) + 5's Rightmost bit (1)] DP with Integer Division + Bit Shift - Bit Manipulation/Bit Manipulation
def countBits(self, n: int) -> List[int]:
# Dynamic Programming + Bit Manipulation
# For every number i in [0, n], compute the number of set bits (1s)
# Idea:
# Reuse previously computed results using DP
# Bit Properties:
# 1. n & 1 = returns rightmost bit (1 if set, 0 if not)
# 2. n >> 1 = shift all bits right by one position
# - i >> 1 gives the number without its last bit
# - (i & 1) tells whether that removed bit was a 1
# (101) == (10) + 1 Example:
# i = 5 => (101)
# 5 >> 1 = 2 => (10)
# dp[5] = dp[2] + 1
# dp[i] = number of set bits in i
# dp[0] = 0 by definition
# sc: O(n)
res = [0] * (n+1)
# Build DP Bottom Up
# tc: O(n)
for i in range(1, n + 1):
# Remove lowest bit
prev_num_removing_rightmost = i >> 1
# Check lowest bit
current_num_rightmost_bit = i & 1
# DP Recurrence:
# dp[i] = dp[i >> 1] + (i & 1)
# bits(i) = bits(i without last bit) + last bit (may be set or unset)
res[i] = res[prev_num_removing_rightmost] + current_num_rightmost_bit
# overall: tc O(n)
# overall: sc O(n)
return res190. 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 Input | Output |
|---|---|
| n = 43261596 | 964176192 |
| n = 2147483644 | 1073741822 |
Constraints:
0 ≤ n ≤ 231 - 2
n is even
Abstraction
Reverse bits of a 32 signed integer.
Space & Time Complexity
| Solution | Time Complexity | Space Complexity | Time Remark | Space Remark |
|---|---|---|---|---|
| Bug | Error |
|---|---|
Brute Force:
| Aspect | Time Complexity | Space Complexity | Time Remarks | Space Remarks |
|---|---|---|---|---|
Find the Bug:
Solution 1: Iterative Bit Manipulation - Bit Manipulation/Bit Manipulation
def reverseBits(self, n: int) -> int:
# Iterative Bit Manipulation
# Reverse all 32 bits of an integer
# Idea:
# Build teh result one bit at a time
# Process:
# - Read n from right to left (Least Significant/Smallest to Most Significant/Largest)
# - Build result from left to right
# Running result stores reversed bits build so far
# sc: O(1)
reversed = 0
# Iterate over 32 bits (problem constraint)
# tc: O(1)
for _ in range(32):
# Shift result left
# Creates space for next incoming bit
# tc: O(1)
reversed <<= 1
# Grab lowest/rightmost bit from n (0 or 1)
# tc: O(1)
rightmost_digit = n & 1
# Add
# tc: O(1)
reversed |= rightmost_digit
# Shift n right:
# Prepare next bit for extraction
# tc: O(1)
n >>= 1
# overall: tc O(32) =~ O(1)
# overall: sc O(1)
return reversed268. 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 Input | Output |
|---|---|
| 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
| Solution | Time Complexity | Space Complexity | Time Remark | Space Remark |
|---|---|---|---|---|
| Bug | Error |
|---|---|
Brute Force:
| Aspect | Time Complexity | Space Complexity | Time Remarks | Space Remarks |
|---|---|---|---|---|
Find the Bug:
Solution 1: Verify Against Math Formula - Bit Manipulation/Bit Manipulation
def missingNumber(self, nums: List[int]) -> int:
# Math Approach:
# Find missing number from range [0, n]
# Idea:
# Compare Excepted vs Actual Sum
# - sum of [0, n]
# - actual sum of array
# sum(0..n) = n * (n+1) // 2
# missing number = expected_sum - actual sum
n = len(nums)
# Sum of numbers 0 to n
expected_sum = n * (n + 1) // 2
# Running sum of array elements
actual_sum = 0
# tc: O(n)
for n in nums:
actual_sum += n
# Compute missing value
missing = expected_sum - actual_sum
# overall: tc O(n)
# overall: sc O(1)
return missingSolution 2: [XOR] Cancel Duplicates Trick - Bit Manipulation/Bit Manipulation
def missingNumber(self, nums: List[int]) -> int:
# XOR Cancellation Trick
# Find missing number from range [0, n]
# Idea:
# XOR cancels duplicates
# XOR Properties:
# 1. a ^ a = 0 (duplicates cancel)
# 2. a ^ 0 = a (identity)
# 3. XOR is commutative + associative
# If we XOR:
# all indices (0..n)
# with all array values
# every paired number cancels, leaving only the missing number
n = len(nums)
# Running XOR Result
# Holds XOR of processed indices and numbers
# sc: O(1)
missing = 0
# tc: iterate over n O(n)
for i in range(n + 1):
# XOR current index
missing ^= i
# XOR Corresponding value (if exists)
if i < n:
missing ^= nums[i]
# overall: tc O(n)
# overall: sc O(n)
return missing371. 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 Input | Output |
|---|---|
| a = 1, b = 2 | 3 |
| a = 2, b = 3 | 5 |
Constraints:
Abstraction
Given two integers, return the sum without using operators.
Space & Time Complexity
| Solution | Time Complexity | Space Complexity | Time Remark | Space Remark |
|---|---|---|---|---|
| Bug | Error |
|---|---|
Brute Force:
| Aspect | Time Complexity | Space Complexity | Time Remarks | Space Remarks |
|---|---|---|---|---|
Find the Bug:
Solution 1: Bit Manipulation - Bit Manipulation/Bit Manipulation
def getSum(self, a: int, b: int) -> int:
# Bit Manipulation Addition
# Add two integers without '+' or '-'
# Idea:
# Binary addition can be split into:
# 1. XOR (^) => sum WITHOUT carry
# 2. AND (&) => determine if bits exist
# 3. AND (&) + left shift (<<) => carry bits
# Example Truth Table:
# -------------------------------
# a b XOR(sum) Carry
# 0 0 0 0
# 0 1 1 0
# 1 0 1 0
# 1 1 0 1
# Variables:
# sum_without_carry = a ^ b
# carry = (a & b) << 1
# Repeat until carry becomes 0
# Python Specific:
# Python integers are unlimited in size,
# but this problem expects 32-bit signed integers range: -2^31 => 2^31 - 1
# Example:
# a = 4294967295
# 32-bit binary = 11111111 11111111 11111111 11111111
# python sees = +4294967295
# Two's Complement Rule:
# This differs from pythons view, here the leftmost bit acts as the sign bit
# Leftmost bit = sign bit
# 1 => negative number
# 0 => positive number
# Example:
# a = 4294967295
# 32-bit binary = 11111111 11111111 11111111 11111111
# Two's Complement Sees = -1
# So we check:
# if a > maxInt:
# as this number should be negative
# Converting 32-bit Unsigned Integer To 32-bit Signed Integer
# ~(a ^ MASK)
# Mask to limit to 32 bits
MASK = 0xFFFFFFFF
# MaxInt to compare 32-bit Unsigned at the end
maxInt = 2**31 - 1
# tc: iterate while carry is not 0 O(?)
while b != 0:
# Sum without carry:
# XOR keeps bits where exactly one is set
xor_sum = a ^ b
# restrict to 32 bits
sum = xor_sum & MASK
# Carry Calculation:
# AND finds positions where BOTH bits are 1 (results in a carry)
carry_bits = a & b
# shift carry to next higher bit position
shifted_carry = carry_bits << 1
# restrict to 32 bits
carry = shifted_carry & MASK
# Update for the next iteration
a = sum
b = carry
# If result exceeds max signed int,
# we must converted a 32-bit unsigned value into a 32-bit signed
if a <= maxInt:
res = a
else:
# Conversion from 32-bit unsigned integer to 32-bit signed integer:
# flip bits outside mask range
flipped = a ^ MASK
# apply bitwise NOT
res = ~flipped
# overall: tc O(1)
# overall: sc O(1)
return res7. 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 Input | Output |
|---|---|
| x = 123 | 321 |
| x = -123 | -321 |
| x = 120 | 21 |
Constraints:
-231 ≤ x ≤ 231 - 1
Abstraction
Given a 32-bit integer, reverse it.
Space & Time Complexity
| Solution | Time Complexity | Space Complexity | Time Remark | Space Remark |
|---|---|---|---|---|
| Bug | Error |
|---|---|
Brute Force:
| Aspect | Time Complexity | Space Complexity | Time Remarks | Space Remarks |
|---|---|---|---|---|
Find the Bug:
Solution 1: Iterative Math Approach - Bit Manipulation/Bit Manipulation
def reverse(self, x: int) -> int:
# Reverse Integer Iteratively:
# Idea:
# Extract digits from right to left using (mod 10)
# Append to result by multiplying current result by 10 and adding the digit
# Track sign separately
# Ensure 32-bit signed integer overflow check
# 32-bit signed integer limits
maxInt = 2**31 - 1 # 2147483647
minInt = -2**31 # -2147483648
# Reversed Result
# sc: O(1)
res = 0
# Tracking Sign
sign = 1 if x >= 0 else -1
# Work with absolute value
x = abs(x)
# Process digits iteratively
while x != 0:
# Grab rightmost digit
digit = x % 10
# Remove digit from x
x //= 10
# Overflow Check:
# If res*1- + digit would exceed 32-bit signed integer, return 0
# Example:
# res = 214748364, digit = 8
# res*10 + digit = 2147483648 > intMax => overflow
# Check overflow before multiplying by 10
if res > (maxInt - digit) // 10:
return 0
# Append digit to revered number
# res_new = res*10 + digit
res = res * 10 + digit
# Apply original sign
# Positive number => same
# Negative number => multiply by -1
res1 = sign * res
# overall: tc O(log10(x))
# overall: sc O(1)
return res1