Problem

Given a non-negative integer n, find the position of the rightmost unset (zero) bit in its binary representation.

Positions in this page are 1-based (i.e., least-significant bit has position 1). Return -1 if no unset bit exists in the considered word (or 0 for a mask result — see each method).

Examples

Example 1

1
2
Input: n = 11  # 0b1011
Output: 2

Example 2

1
2
Input: n = 6   # 0b110
Output: 1

Example 3

1
2
Input: n = 13  # 0b1101
Output: 2

Solution

We present three approaches: isolate mask using ~n & (n+1), scan bits, and a logarithm-based variant. Method 1 is preferred.

Intuition

Adding 1 to n flips the least-significant unset bit to 1 and clears any lower set bits. Bitwise ~n turns unset bits to 1. Intersection ~n & (n+1) therefore isolates the rightmost unset bit as a mask.

Approach

  • If n has all bits set for the considered word width, there may be no unset bit — decide on sentinel (-1 for position).
  • Compute mask = (~n) & (n + 1).
  • To obtain 1-based position from mask, compute the index of the single set bit in mask.

Edge cases:

  • n == ~0u for fixed-width words → no unset bits (return -1).

Code

1
2
3
4
5
6
7
8
class Solution {
 public:
  int rightmost_unset_pos(unsigned int n) {
    unsigned int mask = (~n) & (n + 1u);
    if (mask == 0u) return -1; // no unset bit in this word
    return __builtin_ctz(mask) + 1;
  }
};
1
2
3
4
5
6
7
8
9
package main

import "math/bits"

func RightmostUnsetPos(n uint32) int {
    mask := (^n) & (n + 1)
    if mask == 0 { return -1 }
    return bits.TrailingZeros32(mask) + 1
}
1
2
3
4
5
6
7
class Solution {
    public int rightmostUnsetPos(int n) {
        int mask = (~n) & (n + 1);
        if (mask == 0) return -1;
        return Integer.numberOfTrailingZeros(mask) + 1;
    }
}
1
2
3
4
5
6
class Solution:
    def rightmost_unset_pos(self, n: int) -> int:
        mask = (~n) & (n + 1)
        if mask == 0:
            return -1
        return mask.bit_length()

Complexity

  • ⏰ Time complexity: O(1) — bitwise operations on fixed-size words.
  • 🧺 Space complexity: O(1).

Method 2 — Right-to-left scan

Intuition

Check bits from LSB moving left until an unset bit (0) is found.

Approach

  • If considering infinite-width integers, n always has unset bits; for fixed-width, check full width.
  • Initialize pos = 1.
  • While (n & 1) == 1: n >>= 1, pos += 1.
  • Return pos.

Code

1
2
3
4
5
6
7
8
class Solution {
 public:
  int rightmost_unset_scan(unsigned int n) {
    int pos = 1;
    while ((n & 1u) == 1u) { n >>= 1; ++pos; }
    return pos;
  }
};
1
2
3
4
5
6
7
8
func RightmostUnsetScan(n uint) int {
    pos := 1
    for (n & 1) == 1 {
        n >>= 1
        pos++
    }
    return pos
}
1
2
3
4
5
6
7
class Solution {
    public int rightmostUnsetScan(int n) {
        int pos = 1;
        while ((n & 1) == 1) { n >>= 1; pos++; }
        return pos;
    }
}
1
2
3
4
5
6
7
class Solution:
    def rightmost_unset_scan(self, n: int) -> int:
        pos = 1
        while (n & 1) == 1:
            n >>= 1
            pos += 1
        return pos

Complexity

  • ⏰ Time complexity: O(b) where b is the number of consecutive trailing set bits.
  • 🧺 Space complexity: O(1).

Intuition

If mask = (~n) & (n+1) isolates the unset-bit as a power-of-two, then position = 1 + log2(mask).

Approach

  • Compute mask = (~n) & (n+1).
  • Compute pos = 1 + floor(log2(mask)) (avoid floating rounding issues).

Code

1
2
3
4
5
int rightmost_unset_log(unsigned int n) {
  unsigned int mask = (~n) & (n + 1u);
  if (mask == 0u) return -1;
  return 1 + static_cast<int>(std::log2(mask));
}
1
2
3
4
5
int rightmostUnsetLog(int n) {
  int mask = (~n) & (n + 1);
  if (mask == 0) return -1;
  return 1 + (int)(Math.log(mask) / Math.log(2));
}
1
2
3
4
5
6
def rightmost_unset_log(n: int) -> int:
    mask = (~n) & (n + 1)
    if mask == 0:
        return -1
    from math import log2
    return 1 + int(log2(mask))

Complexity

  • ⏰ Time complexity: O(1).
  • 🧺 Space complexity: O(1).

Notes & References

  • Method 1 is robust and efficient; prefer platform builtins for trailing-zero counts when available.
  • Source examples are listed in source_links in frontmatter.