Medium草稿★★★★★O(n log n) 時間 · O(n) 空間
GreedyHash MapSorting
Patterns🪙 貪心#️⃣ 雜湊🔢 排序後處理
尚未複習過

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

846Hand of StraightsGreedyMediumGreedy

給定一組整數牌 hand 和一個整數 groupSize,判斷能否將所有牌分成若干組,每組包含 groupSize 張連續的牌。

Example:

Input: hand = [1,2,3,6,2,3,4,7,8], groupSize = 3 Output: true ([1,2,3], [2,3,4], [6,7,8])

Intuition

TIP

從最小的牌開始,貪心地組成連續序列;若任何一張需要的牌不夠用,則不可能。

Approaches

1. Sort + HashMap — O(n log n) / O(n)
  • Idea: 排序後遍歷,對每張牌嘗試作為新組的起點,依序消耗連續的牌。
  • Time: O(n log n),排序主導
  • Space: O(n)
class Solution {
    fun isNStraightHand(hand: IntArray, groupSize: Int): Boolean {
        if (hand.size % groupSize != 0) return false
        val count = TreeMap<Int, Int>()
        for (card in hand) {
            count[card] = (count[card] ?: 0) + 1
        }
        while (count.isNotEmpty()) {
            val first = count.firstKey()
            for (i in first until first + groupSize) {
                val c = count[i] ?: return false
                if (c == 1) {
                    count.remove(i)
                } else {
                    count[i] = c - 1
                }
            }
        }
        return true
    }
}
⭐ 2. Sort + HashMap (optimized scan) — O(n log n) / O(n)
  • Idea: 排序後用陣列遍歷,每次遇到尚有剩餘的牌就作為起點,減少 TreeMap 的常數開銷。
  • Time: O(n log n)
  • Space: O(n)
class Solution {
    fun isNStraightHand(hand: IntArray, groupSize: Int): Boolean {
        if (hand.size % groupSize != 0) return false
        hand.sort()
        val count = HashMap<Int, Int>()
        for (card in hand) {
            count[card] = (count[card] ?: 0) + 1
        }
        for (card in hand) {
            if ((count[card] ?: 0) == 0) continue
            for (i in card until card + groupSize) {
                val c = count[i] ?: return false
                if (c == 0) return false
                count[i] = c - 1
            }
        }
        return true
    }
}

🔑 Takeaways