Medium草稿★★★★★O(C(n,k) * k) 時間 · O(k) 空間
BacktrackingRecursion
Patterns🌿 回溯
尚未複習過

解法已隱藏 — 先讀題目敘述、自己想想看,再點上方按鈕揭曉。

77CombinationsBacktrackingMediumBacktracking

給定兩個整數 nk,回傳從 1n 中選 k 個數的所有組合。可以任意順序回傳。

Example:

Input: n = 4, k = 2 Output: [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]

Intuition

TIP

核心思路:回溯法從 start 開始向後選數,選滿 k 個時收集結果。

Approaches

1. Basic Backtracking — O(C(n,k) * k) / O(k)
  • Idea: 從 start 開始遍歷到 n,每次選一個數後遞迴,回溯時移除
  • Time: O(C(n,k) * k) - 共 C(n,k) 個組合,每個複製需 O(k)
  • Space: O(k) - 遞迴深度
class Solution {
    fun combine(n: Int, k: Int): List<List<Int>> {
        val result = mutableListOf<List<Int>>()
        val current = mutableListOf<Int>()

        fun backtrack(start: Int) {
            if (current.size == k) {
                result.add(ArrayList(current))
                return
            }

            for (i in start..n) {
                current.add(i)
                backtrack(i + 1)
                current.removeAt(current.lastIndex)
            }
        }

        backtrack(1)
        return result
    }
}
⭐ 2. Backtracking + Pruning — O(C(n,k) * k) / O(k)
  • Idea: 在基本回溯上加入剪枝:若剩餘可選數量不足以填滿組合,提前終止
  • Time: O(C(n,k) * k)
  • Space: O(k)
class Solution {
    fun combine(n: Int, k: Int): List<List<Int>> {
        val result = mutableListOf<List<Int>>()
        val current = mutableListOf<Int>()

        fun backtrack(start: Int) {
            if (current.size == k) {
                result.add(ArrayList(current))
                return
            }

            val need = k - current.size
            // 剪枝:從 start 到 n 至少要有 need 個數
            for (i in start..n - need + 1) {
                current.add(i)
                backtrack(i + 1)
                current.removeAt(current.lastIndex)
            }
        }

        backtrack(1)
        return result
    }
}

🔑 Takeaways

Ladders 看全部 →