---
# System prepended metadata

title: Q4. Find Nth Smallest Integer with K One Bits
tags: [Leetcode]

---

# Q4. Find Nth Smallest Integer with K One Bits

**練習日期：** 2026-01-25
**類型：** Weekly Contest 486


## 📘 題目敘述

給你兩個正整數 `n` 和 `k`。

請回傳「二進位表示中 **恰好有 `k` 個 1**」的正整數裡，第 `n` 小的那一個。

題目保證答案 **嚴格小於 `2^50`**。


### 條件限制

* `1 <= n <= 250`
* `1 <= k <= 50`
* 答案嚴格小於 `2^50`


## 🧠 解題思路（最後TLE）

我的想法是：
我先用一個 `bin`（bool 陣列）表示「目前這個數的二進位哪些位元是 1」，並且從最小的開始（也就是最低位連續放 `k` 個 1：`111...000`）。

接著我要做的事情就是重複 `n-1` 次：
**把目前的 bitmask 變成「下一個更大的、但 1 的數量仍然是 k」的 bitmask**。

這其實是在做「固定 1 的個數的下一個組合（next combination）」。


### 所有變數

* `n, k`：題目輸入，要找第 `n` 小、且有 `k` 個 1 的正整數
* `bin`：`vector<bool>`，`bin[t] = true` 代表第 `t` 個 bit 是 1（我用 `t=0` 當最低位）
* `pos`：目前最高的 1 出現到哪個 bit（用來最後把 `bin` 轉回數字時的最高位）
* `ans`：最後要回傳的整數
* `orot / nrot`（這題沒有）
* `count`：掃描過程中，累計「目前遇到的 1 的數量」（用來把低位重新塞回去）
* `i, j, l`：迴圈索引用


## 🪜 主要流程步驟

### 1) 初始化成「最小的那個」

* 最小的數一定是：最低位開始連續放 `k` 個 1
  例如 `k=3` → `0b111`

所以我先做：

* `bin[0..k-1] = true`
* 其餘都是 `false`

---

### 2) 重複做 `n-1` 次：產生下一個 bitmask（核心）

我在每一次迭代裡，從低位往高位掃描，找「可以往左移動的一顆 1」：

#### 我在找的關鍵形狀

* 找到某個位置 `j` 滿足：

  * `bin[j] == 1`
  * `bin[j+1] == 0`

這代表這顆 1 可以「往更高位推一格」，讓整體數值變大，但仍保留 k 個 1。

#### 做法分兩步

**(A) 把這顆 1 往左推**

* `bin[j] = 0`
* `bin[j+1] = 1`
* 同時更新 `pos = max(pos, j+1)`（因為最高位可能變大了）

**(B) 把 `j` 左邊的低位重新整理成「最小」**

* 我會用 `count` 記錄我一路走來遇到多少個 1（包含要搬的那顆之前累積的）
* 當找到可搬動位置後，我就把 `0..j-1` 的 bit 重新排成：

  * 從最低位開始塞回 `count` 顆 1
  * 其餘補 0
    這樣可以確保：
    在「固定高位變大的前提下」，低位保持最小，才能得到「下一個最小的合法數」。

---

### 3) 把 `bin` 轉回整數

最後我從 `pos`（最高位）一路往 `0` 組回去：

* 每一位做：`ans = ans * 2 + (bin[l] ? 1 : 0)`


## 💻 程式碼實作

```cpp
class Solution {
public:
    long long nthSmallest(long long n, int k) {
        long long int ans = 0;
        int pos = k - 1;
        vector<bool> bin(51, false);
        for (int i = 0; i < k; i++) {
            bin[i] = true;
        }
        for (long long int i = 1; i < n; i++) {
            int count = 0;
            for (int j = 0; j < 50; j++) {
                if (bin[j] && !bin[j + 1]) {
                    bin[j + 1] = true;
                    bin[j] = false;
                    pos = (pos > j + 1) ? pos : (j + 1);
                    for (int k = 0; k < j; k++) {
                        if (count > 0) {
                            bin[k] = true;
                            count--;
                        } else {
                            bin[k] = false;
                        }
                    }
                    break;
                } else if (bin[j]) {
                    count++;
                }
            }
        }
        for (int l = pos; l >= 0; l--) {
            ans = ans * 2 + (bin[l] ? 1 : 0);
        }
        return ans;
    }
};
```


## 🔗 題目連結
https://leetcode.com/contest/weekly-contest-486/problems/find-nth-smallest-integer-with-k-one-bits/description/
