采用快慢指针办法破循环

来源于leetcode的一道简单难度的算法题“快乐数

     算法要求:给定一个任意数字,数字的每一位都可拆解为多个一位数(19 -> 1,9   234 -> 2,3,4),所有的一位数做平方和之后产生新的数字(19 -> 1,9.   sum = 1*1 + 9*9 ,sum为新的值)之后,重复上述拆解及平方和操作,直到最后得到的结果为1,就是快乐数

     这里我本来的想法是通过递归去不断的拆解循环,终止条件为直到找到为1的结果。但会产生一个问题,并不是所有数都能最终得到1的值,有的数会卡在一个循环里永远也得不到1的值,会在某个数形成环,最终无限循环下去导致stackOverFlow。

那么为了解决这个问题呢,就必须去判断到底是在哪个数形成了没有出口的环

     为什么要判断这个呢,因为哪怕是快乐数最终的值“1”,如果他没有终止条件(判断为1)还是会不断循环下去,1的平方还是1,也就是说其实跟其他的值循环没有区别的,主要是1的这个值可以被终止,但其他的随机值没有办法终止循环,所以这个时候就要找到其他循环的数去判断是否是“1”,如果是“1”则是快乐数,不是的话就可以返回false了(都陷入循环了,不返回也不会有期待值)

这里判断哪个数形成了环的思路,可以考虑是哪个数第一次出现了重复的值(意味着绕了一圈又回到了起点)

     初步可以考虑通过Set去实现,将每一个结果值都放入Set中,直到有一次放入结果值的时候并没有成功放进去(Set不接受重复的数),就可以判断出是哪个数形成了环

比较好的处理办法则是通过快慢指针的办法

快慢指针:两个不同的指针,同一时间内,快的一次走两步,慢的走一步。当遇到循环时,两个指针都在循环中走,而最后的结果是:快指针必然会追上慢指针,他们重合(追上)的地方的值,就是开始出现循环的值。可以通过这个办法很轻松的找出循环的入口。

贴一段实现的Java代码:

class Solution {
    public boolean isHappy(int n) {
		int fast = n; int slow = n;
		do {
          	//慢指针一次走一步
			slow = getSum(slow);
          	//快指针一次走两步
			fast = getSum(fast);
			fast = getSum(fast);
		}while (fast != slow);
      	//快慢指针相遇判断值
		if(fast == 1){
			return true;
		}
		return false;
    }
  	//处理每一个值
    public int getSum(int n){
    	int sum = 0;
    	int a = 0;
    	while (n > 0){
    		a = n%10;
    		sum += (a*a);
    		n = n/10;
		}
    	return sum;
	}
}
posted @ 2021-12-07 15:10  YanSss  阅读(63)  评论(0编辑  收藏  举报