Q4. Find Nth Smallest Integer with K One Bits

練習日期:2026-01-25

難度:Hard

類型:Weekly Contest 486

📘 題目敘述

給你兩個正整數 nk

請回傳「二進位表示中 恰好有 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 的正整數
  • binvector<bool>bin[t] = true 代表第 t 個 bit 是 1(我用 t = 0 當最低位)
  • pos:目前最高的 1 出現到哪個 bit(用來最後把 bin 轉回數字時的最高位)
  • ans:最後要回傳的整數
  • count:掃描過程中,累計「目前遇到的 1 的數量」(用來把低位重新塞回去)
  • i, j, l:迴圈索引用

🪜 主要流程步驟

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

  • 最小的數一定是:最低位開始連續放 k 個 1,例如 k = 30b111
  • 所以我先做:
    • 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)

💻 程式碼實作

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/

作者: scottnick
撰寫日期: 2026-01-25
類別:
原文連結: https://scottnick.github.io/cpp-notes/contests/weekly-contest-486/q4-find-nth-smallest-integer-with-k-one-bits.html