一、题目描述
编写一个算法来判断一个数 n
是不是快乐数。
「快乐数」 定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n
是 快乐数 就返回 true
;不是,则返回 false
。
示例 1:
输入:n = 19 输出:true 解释: 1^2 + 9^2 = 82 8^2 + 2^2 = 68 6^2 + 8^2 = 100 1^2 + 0^2 + 0^2 = 1
示例 2:
输入:n = 2 输出:false
提示:
1 <= n <= 2^31 - 1
二、解题思路
- 创建一个辅助函数
getNext(int n)
,用于计算一个数的每一位数字的平方和。 - 使用快慢指针的方法来判断是否存在循环。快指针每次移动两步,慢指针每次移动一步。如果存在循环,快慢指针最终会相遇;如果不存在循环,快指针最终会到达1。
- 在主函数
isHappy(int n)
中,初始化快慢指针,并开始循环。如果快指针到达1,则返回true
;如果快慢指针相遇,则返回false
。
三、具体代码
class Solution {
public boolean isHappy(int n) {
int slow = n;
int fast = getNext(n);
while (fast != 1 && slow != fast) {
slow = getNext(slow);
fast = getNext(getNext(fast));
}
return fast == 1;
}
private int getNext(int n) {
int sum = 0;
while (n > 0) {
int digit = n % 10;
sum += digit * digit;
n /= 10;
}
return sum;
}
}
这段代码中,getNext
函数负责计算一个数的每一位数字的平方和。在 isHappy
函数中,我们使用快慢指针的方法来判断是否为快乐数。如果快指针到达1,说明找到了快乐数;如果快慢指针相遇,说明进入了循环,不是快乐数。
四、时间复杂度和空间复杂度
1. 时间复杂度
-
getNext
函数:对于每次调用getNext
函数,它会计算一个数的每一位数字的平方和。对于一个整数n
,假设它有d
位,那么getNext
函数会执行d
次循环。在每次循环中,我们执行了常数时间的操作(取余、乘法、加法和除法)。因此,getNext
函数的时间复杂度是 O(d),其中 d 是数字 n 的位数。 -
isHappy
函数:快指针每次移动两步,慢指针每次移动一步。在最好的情况下,如果 n 是一个快乐数,快指针会在达到 1 之前移动 log(n) 次(因为每次调用getNext
函数都会减少 n 的大小)。在最坏的情况下,如果 n 不是快乐数,快慢指针会在进入循环之前移动 log(n) 次。一旦进入循环,快慢指针相遇最多需要 O(m) 次,其中 m 是循环的长度。由于 m 通常很小(例如,对于不是快乐数的数,循环长度是 1 到 8),我们可以认为isHappy
函数的时间复杂度是 O(log(n))。
综上所述,整个算法的时间复杂度是 O(log(n)),因为每次 getNext
的调用时间复杂度是 O(d),而 isHappy
的总调用次数是 O(log(n))。
2. 空间复杂度
-
getNext
函数:它只使用了常数额外空间(用于存储sum
和digit
变量),所以空间复杂度是 O(1)。 -
isHappy
函数:同样,它也只使用了常数额外空间(用于存储slow
和fast
变量),所以空间复杂度也是 O(1)。
因此,整个算法的空间复杂度是 O(1),因为算法使用了固定数量的额外空间,不随输入大小 n 变化。
五、总结知识点
-
循环控制:
while
循环用于在满足特定条件时重复执行代码块。
-
数学运算:
- 取余操作
%
用于获取一个整数的最后一位数字。 - 除法操作
/
用于去掉一个整数的最后一位数字。
- 取余操作
-
递归思想:
getNext
函数通过递归计算一个数的每位数字的平方和,虽然这里用的是循环而非递归函数调用。
-
平方计算:
- 通过
digit * digit
计算一个数字的平方。
- 通过
-
变量赋值:
- 变量
sum
用于累加每位数字的平方和。
- 变量
-
逻辑判断:
- 使用
!=
进行不等比较。 - 使用
&&
进行逻辑与运算。
- 使用
-
辅助函数:
getNext
是一个辅助函数,用于封装计算平方和的逻辑,提高代码的可读性和复用性。
-
快慢指针技术:
- 快慢指针用于检测循环。这是检测链表是否有环的一种通用技术,在这里用来检测一个数是否是快乐数。
-
整数处理:
- 处理整数时,需要注意整数溢出的问题。在这个问题中,由于每次操作都是取余和除法,所以不会发生溢出。
以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。