题目
编写一个算法来判断一个数 n
是不是快乐数。
「快乐数」 定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n
是 快乐数 就返回 true
;不是,则返回 false
。
提示:
1 <= n <= 231 - 1
方法 :快慢指针法
分析
首先我们需要理解如何判断一个数为快乐数? 我们拿例子1来说
所谓的快乐数,就是把这个数字n的所有位数拆开后所得到的这个平方和。如果这个平方和经过一系列这样的操作后等于1,那么这个数就是快乐数;
那么这就会可能涉及到几个方面:
- n经过操作后平方和等于1,该数位快乐数
- n经过操作后得到了和之前相同的数->进入到循环,这个数不是快乐数
- n经过操作后数值会越来越大;
对于这个进入循环的情况,我们可以联想到141. 环形链表 - 力扣(LeetCode)https://leetcode.cn/problems/linked-list-cycle/description/这一题,该题目可以根据龟兔赛跑的思想,不论兔子和乌龟循环的节点在哪,只要兔子和乌龟能够相遇,就证明这个链中形成一个环。因为在同一个行进方向上,兔子比乌龟多走一格。
同理,本题我们会计算每次操作的平方和
// 计算一个数每位数字的平方和
public int getNext(int n) {
int totalSum = 0;
while (n > 0) {
int d = n % 10;
n /= 10;
totalSum += d*d;
}
return totalSum;
}
getNext方法用来计算一个数每次操作的平方和;而我们反复调用这个方法就会形成一个隐式链表隐式意味着我们没有实际的链表节点和指针,但数据仍然形成链表结构。
意识到我们实际有个链表,那么这个问题就可以转换为检测一个链表是否有环。因此我们在这里可以使用弗洛伊德循环查找算法。这个算法是两个奔跑选手,一个跑的快,一个跑得慢。在龟兔赛跑的寓言中,跑的慢的称为 “乌龟”,跑得快的称为 “兔子”。
具体可以参考
下面是判断是否为快乐数的实现方法
public boolean isHappy(int n) {
int slowRunner = n;
int fastRunner= getNext(n);
while(fastRunner !=1&&slowRunner!=fastRunner){
slowRunner=getNext(slowRunner);
fastRunner=getNext(getNext(fastRunner));
}
return fastRunner ==1;
}
算法中的isHappy
方法使用了快慢指针的技巧。首先,定义了两个指针slowRunner
和
算法中的isHappy
方法使用了快慢指针的技巧。首先,定义了两个指针slowRunner
和fastRunner
,它们的初始值分别为输入的整数n
和getNext(n)
的结果。然后,在一个循环中,不断更新slowRunner
和fastRunner
的值,直到满足以下条件之一:
fastRunner
的值等于1,这时候返回true
,表示输入的整数是一个快乐数;slowRunner
和fastRunner
相等,这意味着出现了循环,返回false
,表示输入的整数不是一个快乐数。
在每次循环中,slowRunner
每次更新一次为getNext(slowRunner)
,而fastRunner
每次更新两次为getNext(getNext(fastRunner))
,这样可以实现快慢指针的效果,从而判断是否存在循环。
如果最终fastRunner
的值为1,则返回true
,否则返回false
,表示输入的整数不是一个快乐数。
这种算法的核心思想是利用快慢指针来判断循环,从而判断一个数是否是快乐数。
,它们的初始值分别为输入的整数n
和getNext(n)
的结果。然后,在一个循环中,不断更新slowRunner
和fastRunner
的值,直到满足以下条件之一:
fastRunner
的值等于1,这时候返回true
,表示输入的整数是一个快乐数;slowRunner
和fastRunner
相等,这意味着出现了循环,返回false
,表示输入的整数不是一个快乐数。
在每次循环中,slowRunner
每次更新一次为getNext(slowRunner)
,而fastRunner
每次更新两次为getNext(getNext(fastRunner))
,这样可以实现快慢指针的效果,从而判断是否存在循环。
如果最终fastRunner
的值为1,则返回true
,否则返回false
,表示输入的整数不是一个快乐数。
这种算法的核心思想是利用快慢指针来判断循环,从而判断一个数是否是快乐数。
代码
class Solution {
// 计算一个数每位数字的平方和
public int getNext(int n) {
int totalSum = 0;
while (n > 0) {
int d = n % 10;
n /= 10;
totalSum += d*d;
}
return totalSum;
}
public boolean isHappy(int n) {
int slowRunner = n;
int fastRunner= getNext(n);
while(fastRunner !=1&&slowRunner!=fastRunner){
slowRunner=getNext(slowRunner);
fastRunner=getNext(getNext(fastRunner));
}
return fastRunner ==1;
}
}