Easy草稿★★★★O(log n) 時間 · O(1) 空間
MathHash TableTwo Pointers
Patterns🐢 快慢指針↔️ 雙指針#️⃣ 雜湊🧮 數學・組合
尚未複習過

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

202Happy NumberMath & GeometryEasyMath & Geometry

判斷一個數字 n 是否為「快樂數」。快樂數的定義:反覆將數字替換為其各位數字的平方和,最終會得到 1。如果進入無限循環且不會到達 1,則不是快樂數。

Example:

Input: n = 19 Output: true (1^2 + 9^2 = 82 -> 8^2 + 2^2 = 68 -> … -> 1)

Intuition

TIP

核心思路:這是一個鏈結串列找環問題——用快慢指標檢測是否會進入循環。

Approaches

1. HashSet Cycle Detection — O(log n) / O(log n)
  • Idea: 用 Set 記錄每次計算的結果,如果出現重複表示進入循環
  • Time: O(log n) - 數字會快速縮小
  • Space: O(log n) - Set 儲存中間結果
class Solution {
    fun isHappy(n: Int): Boolean {
        val seen = HashSet<Int>()
        var num = n
        while (num != 1 && num !in seen) {
            seen.add(num)
            num = getNext(num)
        }
        return num == 1
    }

    private fun getNext(n: Int): Int {
        var sum = 0
        var num = n
        while (num > 0) {
            val digit = num % 10
            sum += digit * digit
            num /= 10
        }
        return sum
    }
}
⭐ 2. Floyd's Fast & Slow Pointers — O(log n) / O(1)
  • Idea: 慢指標每次算一步,快指標每次算兩步。若最終到 1 則是快樂數,若快慢相遇則有環
  • Time: O(log n)
  • Space: O(1) - 只用兩個指標
class Solution {
    fun isHappy(n: Int): Boolean {
        var slow = n
        var fast = getNext(n)
        while (fast != 1 && slow != fast) {
            slow = getNext(slow)
            fast = getNext(getNext(fast))
        }
        return fast == 1
    }

    private fun getNext(n: Int): Int {
        var sum = 0
        var num = n
        while (num > 0) {
            val digit = num % 10
            sum += digit * digit
            num /= 10
        }
        return sum
    }
}
Note: Math Analysis

對於 3 位數以下的數字,各位平方和最大為 9^2 * 3 = 243。因此所有數字最終都會收斂到 243 以下的循環。已知不快樂的數會進入以下循環:4 -> 16 -> 37 -> 58 -> 89 -> 145 -> 42 -> 20 -> 4。

可以直接硬編碼檢查:

class Solution {
    fun isHappy(n: Int): Boolean {
        val cycleMembers = setOf(4, 16, 37, 58, 89, 145, 42, 20)
        var num = n
        while (num != 1 && num !in cycleMembers) {
            num = getNext(num)
        }
        return num == 1
    }

    private fun getNext(n: Int): Int {
        var sum = 0
        var num = n
        while (num > 0) {
            val digit = num % 10
            sum += digit * digit
            num /= 10
        }
        return sum
    }
}

🔑 Takeaways