循环类问题的一个解题思路为:设置一个慢指针,每次步进1,一个快指针,每次步进2,则快慢指针总会出现相遇的情况。比如一个数组[1,2,3,4],快指针和慢指针都从第一个元素开始遍历,如下图,第5趟后他们就相遇了
下面来看今天在leetcode碰到的一道题:验证一个数是否为快乐数?
快乐数的定义如下:
- Starting with any positive integer, replace the number by the sum of the squares of its digits.
- Repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1.
- Those numbers for which this process ends in 1 are happy.
我的第一印象就是使用一个数组来记录这个数是否验证过,如果是就存到数组中,后面再验证鑫生成的数的时候查一下数组是否存在,如果存在就不是快乐数,如果最后生成的数的每个位数平方和为1,则为快乐数,实现代码如下:
/**
* 通过数组检验方式
*/
private boolean isHappyByList(int n){
//初始化list存储每次校验的值
List<Integer> existList = new ArrayList<>();
//校验n是否为快乐数
while(true){
//n为1的时候,则为快乐数
if(n == 1){
return true;
}
//如果n为之前出现过的数,则不是快乐数
if(existList.contains(n)){
return false;
}
//将n标记为出现过的数存入list
existList.add(n);
//count记录n每个位数上的平方值总和
int count =0;
//计算n每个位数上的平方值总和
while(n>0){
int i = n%10;
count += i*i;
n /=10;
}
n = count;
}
}
后面看到评论有同学使用了快慢指针,仔细一想,这种数的计算就是一个循环问题,实现代码如下:
/**
* 通过快慢指针方式
* 设置一个慢指针每次计算一次,一个快指针每次计算两次
* 快乐数最后两个指针结果都是1
* 非快乐数会存在循环,则慢指针总会赶上快指针
*/
private boolean isHappyByPoint(int n){
int slow = n, fast = n;
do {
slow = dealNum(slow);
fast = dealNum(fast);
fast = dealNum(fast);
} while (slow != fast);
return slow == 1;
}
/**
* 计算一个数每个位数上的数值的平方和
*/
private int dealNum(int n){
int count =0;
//计算n每个位数上的平方值总和
while(n>0){
int i = n%10;
count += i*i;
n /=10;
}
return count;
}
总结,遇到类似问题的时候,如果发现是循环问题,应该尝试从快慢指针的角度出发考虑,会有解题的惊喜!