【LeetCode】202. 快乐数
解题思路
快乐数问题的核心在于循环检测,主要有两种解法:
- 哈希集合法:记录所有出现过的数字,若重复出现则判定为循环(时间复杂度 O(n),空间复杂度 O(n))。
 - 快慢指针法:利用龟兔赛跑算法检测循环,无需额外存储空间(时间复杂度 O(n),空间复杂度 O(1))。
 
以下采用快慢指针法实现,这是空间最优的解法。
关键步骤
- 平方和计算:将数字按位分解,计算各位平方和(如 19 → 1²+9²=82)。
 - 循环检测:
- 定义慢指针 
slow(每次计算一次平方和)和快指针fast(每次计算两次平方和)。 - 若快慢指针相遇且值为 1,则为快乐数;否则存在循环,返回 false。
 
 - 定义慢指针 
 
Golang代码实现
func isHappy(n int) bool { // 边界条件:直接返回1的情况 if n == 1 { return true } // 快慢指针初始化 slow, fast := n, bitSquareSum(n) // 循环检测(快指针可能先到1) for fast != 1 && slow != fast { slow = bitSquareSum(slow) // 慢指针走一步 fast = bitSquareSum(bitSquareSum(fast)) // 快指针走两步 } return fast == 1 } // 计算数字的各位平方和 func bitSquareSum(n int) int { sum := 0 for n > 0 { digit := n % 10 // 取个位数 sum += digit * digit n /= 10 // 移除已处理的位数 } return sum }
复杂度分析
| 指标 | 值 | 说明 | 
|---|---|---|
| 时间复杂度 | O(n) | 最坏情况下遍历数字链长度 | 
| 空间复杂度 | O(1) | 仅使用固定变量,无额外存储 | 
代码解析
- 
快慢指针逻辑
- 快指针每次移动两步,慢指针移动一步。若存在循环,两者必定相遇。
 - 示例:对于 
n=2,计算链为2 → 4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4,快慢指针最终会在4处相遇,返回 false。 
 - 
平方和计算函数
- 通过取余和整除操作逐位处理数字(如 
19 → 1和9 → 1+81=82)。 
 - 通过取余和整除操作逐位处理数字(如 
 - 
边界处理
- 若输入为 1,直接返回 true。
 - 若快指针先到达 1,立即终止循环(如 
n=7的快乐数链)。 
 
运行示例验证
func main() { fmt.Println(isHappy(19)) // 输出: true(示例1) fmt.Println(isHappy(2)) // 输出: false(示例2) fmt.Println(isHappy(7)) // 输出: true(快乐数) fmt.Println(isHappy(4)) // 输出: false(进入循环) }
扩展讨论
- 
数学规律优化
不快乐数最终会进入4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4的循环。若检测到4可直接返回 false:func bitSquareSum(n int) int { sum := 0 for n > 0 { digit := n % 10 sum += digit * digit n /= 10 if sum > 4 { // 提前终止不必要的计算 break } } return sum }
该优化可减少部分计算次数,但需权衡条件判断的开销。
 - 
哈希集合法对比
func isHappyHash(n int) bool { seen := make(map[int]bool) for n != 1 && !seen[n] { seen[n] = true n = bitSquareSum(n) } return n == 1 }
该方法更直观,但需额外 O(n) 空间存储已出现数字。
 
总结
快慢指针法通过循环检测机制和空间优化,成为解决快乐数问题的标准解法。该实现兼顾效率与代码简洁性,完美覆盖所有测试用例。
                    
                
                
            
        
浙公网安备 33010602011771号