Skip to content

191. Number of 1 Bits (Easy)

Problem

Write a function that takes an unsigned integer and returns the number of 1 bits it has (popcount).

Example

  • n = 0b10113
  • n = 0b100000001

LeetCode 191 · Link · Easy

Try it yourself

idle

Starter code: this editor begins with intentional TODOs. Fill the function, run the embedded tests, then compare your solution with the worked approaches below.

Click Run Python to execute. First run downloads Python (~10 MB, cached after that).

Approach 1: Shift and test each bit

def hamming_weight(n):
count = 0
while n: # L1: loop up to B iterations (B = bit width)
count += n & 1 # L2: O(1), test LSB
n >>= 1 # L3: O(1), shift right
return count

Where the time goes, line by line

Variables: B = number of bits in n (32 for this problem).

LinePer-call costTimes executedContribution
L1-L3 (shift loop)O(1)O(1)BO(B)O(B) = O(1)O(1) ← dominates (constant)
L2 (test LSB)O(1)O(1)BO(B)O(B)
L3 (shift right)O(1)O(1)BO(B)O(B)

The loop runs at most B = 32 iterations regardless of input value.

Complexity

  • Time: O(B)O(B) where B = number of bits (32 for this problem).
  • Space: O(1)O(1).

Approach 2: Brian Kernighan’s trick (canonical)

n & (n - 1) clears the lowest set bit. Loop until n == 0.

def hamming_weight(n):
count = 0
while n: # L1: loop popcount(n) times
n &= n - 1 # L2: O(1), clear lowest set bit
count += 1 # L3: O(1)
return count

Where the time goes, line by line

Variables: B = number of set bits in the input (32 max).

LinePer-call costTimes executedContribution
L1-L3 (Kernighan loop)O(1)O(1)popcount(n)O(popcount)O(popcount) ← dominates
L2 (clear lowest bit)O(1)O(1)popcount(n)O(popcount)O(popcount)

The loop runs exactly popcount(n) times, not B times. For sparse inputs this is much faster than Approach 1.

Complexity

  • Time: O(popcount)O(popcount). Iterations = number of set bits.
  • Space: O(1)O(1).

Faster than Approach 1 when the integer has few set bits.

Try this approach:

idle
Click Run Python to execute. First run downloads Python (~10 MB, cached after that).

Approach 3: Built-in / bit-parallel tricks

Modern hardware has popcount instructions. Python’s bin(n).count('1') or n.bit_count() (Python 3.10+) compiles to that on supporting platforms. In TypeScript, Math.clz32 counts leading zeros but there is no direct popcount built-in; use Kernighan’s trick instead.

def hamming_weight(n):
return n.bit_count() # L1: O(1) on modern hardware

Where the time goes, line by line

Variables: B = number of bits (32 max for this problem).

LinePer-call costTimes executedContribution
L1 (bit_count)O(1)O(1) hardware1O(1)O(1) ← dominates

On CPUs with a POPCNT instruction this compiles to a single instruction.

Complexity

  • Time: O(1)O(1) on most modern hardware, O(B)O(B) worst.
  • Space: O(1)O(1).

Try this approach:

final class Solution {
func hammingWeight(_ n: UInt32) -> Int {
n.nonzeroBitCount
}
}

Swift notes

UInt32 prevents sign extension during right shifts. The direct scan always checks 32 positions. Kernighan’s loop runs once per set bit. Swift’s nonzeroBitCount expresses the built-in approach directly, but it hides the bit-clearing invariant an interviewer may want to see.

Summary

ApproachTimeSpace
Shift + testO(B)O(B)O(1)O(1)
Kernighan (n &= n - 1)O(popcount)O(popcount)O(1)O(1)
Built-in bit_countO(1)O(1) on modern HWO(1)O(1)

Kernighan’s is the interview-canonical trick. Know it for problem 338 and any “count bits” variant.

Test cases

# Quick smoke tests, paste into a REPL or save as test_191.py and run.
# Uses the canonical implementation (Approach 2: Kernighan's trick).
def hamming_weight(n):
count = 0
while n:
n &= n - 1
count += 1
return count
def _run_tests():
assert hamming_weight(0b1011) == 3
assert hamming_weight(0b10000000) == 1
assert hamming_weight(0) == 0 # edge: zero has no set bits
assert hamming_weight(0xFFFFFFFF) == 32 # edge: all 32 bits set
assert hamming_weight(1) == 1
assert hamming_weight(0b10110111) == 6
print("all tests pass")
if __name__ == "__main__":
_run_tests()
  • None, pure bit arithmetic.
  • Bit Manipulation, the binary representation pattern for masks, toggles, shifts, and arithmetic shortcuts.
  • Math and Number Theory, the arithmetic invariant behind digits, divisibility, modulo behavior, and identities.