Skip to content

202.快乐数

一、问题描述

编写一个算法来判断一个数 n 是不是快乐数。

快乐数的定义是:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是无限循环但始终变不到 1。如果可以变为 1,那么这个数就是快乐数。

示例

plaintext
输入:19
输出:true
解释:
1^2 + 9^2 = 82
8^2 + 2^2 = 68
6^2 + 8^2 = 100
1^2 + 0^2 + 0^2 = 1

二、方案一:哈希表法

1、思路

使用哈希表记录每次计算得到的平方和。如果某个平方和之前出现过,说明进入了循环,此时可以判断该数不是快乐数。如果平方和变为 1,则该数是快乐数。

2、代码实现

go
func isHappy(n int) bool {
    seen := make(map[int]bool)
    for n != 1 && !seen[n] {
        seen[n] = true
        n = nextNumber(n)
    }
    return n == 1
}
func nextNumber(n int) int {
    sum := 0
    for n > 0 {
        digit := n % 10
        sum += digit * digit
        n /= 10
    }
    return sum
}

3、复杂度分析

  • 时间复杂度:O(logn),其中 n 是输入的数字。因为每次迭代都会将数字减少一个或多个数量级。
  • 空间复杂度:O(logn),因为我们需要存储每次迭代的结果。

三、方案二:快慢指针法

1、思路

类似于检测链表中的循环,我们可以使用快慢指针的方法。慢指针每次移动一步,快指针每次移动两步。如果两者相遇,则说明存在循环,该数不是快乐数。如果快指针到达 1,则该数是快乐数。

2、代码实现

go
func isHappy(n int) bool {
    slow, fast := n, nextNumber(n)
    for fast != 1 && slow != fast {
        slow = nextNumber(slow)
        fast = nextNumber(nextNumber(fast))
    }
    return fast == 1
}
func nextNumber(n int) int {
    sum := 0
    for n > 0 {
        digit := n % 10
        sum += digit * digit
        n /= 10
    }
    return sum
}

3、复杂度分析

  • 时间复杂度:O(logn),与方案一相同。
  • 空间复杂度:O(1),因为我们只使用了几个变量来存储慢指针和快指针的值。

四、总结

方案时间复杂度空间复杂度优点缺点
哈希表法O(logn)O(logn)实现简单需要额外空间
快慢指针法O(logn)O(1)空间效率高实现稍微复杂
推荐使用快慢指针法,因为它在空间效率上更优。

木川工作室 (微信:mcmc2024)