【C++】双指针算法:快乐数

发布于:2024-04-24 ⋅ 阅读:(29) ⋅ 点赞:(0)

1.题目

题目中一定要理解快乐数的含义,否则题目难度直逼困难。
在示例1中n=19,经过几步操作后结果变成1。

那么示例2中n=2是什么情况呢:

2->4->16->37->58->89->145->42->20->4(与前面的4形成闭环)

在计算机中int所能存储的数据范围内,只有这两种情况,没有第三种情况,稍后我会进行简单证明,这个证明过程并不重要,能看懂就行。

2.算法思路

那么如何把示例1和示例2联系在一起呢:

其实示例1最终的结果也是一个闭环,只不过这个环中只有一个数字1。

而示例二中的闭环无非就是不止一个数,且不可能有1。

我们就可以通过闭环中有没有1来判断这个数是否是快乐数。

回到算法本身,我们的算法是双指针,但是这道题目只是单纯的数字,难道真的需要定义一个实实在在的指针嘛?其实不是,双指针只是一个思想,像我的前两篇文章中的数组下标可以代表指针,在这篇文章中一个数字也可以代表指针!思想相同,就属于同一类算法。

那么这道题目就可以用快慢指针来解决,定义一个慢指针slow,和一个快指针fast。慢指针进行一次操作,快指针进行两次操作,因为最后的结果是一个闭环,所以快慢指针一定会相遇,相遇时判断它们是否等于1。等于1就是快乐数,否则就不是。

3.提交结果与代码实现

class Solution {
public:
    int GetSum(int x){
        int sum=0;
        while(x){
            int a=x%10;
            x/=10;
            sum+=a*a;
        }
        return sum;
    }
    bool isHappy(int n) {
        int slow=n,fast=n;
        do{
            slow=GetSum(slow);//慢指针走一步
            fast=GetSum(GetSum(fast));//快指针走两步
        }while(slow!=fast);
        return slow==1;
    }
};

4.证明一定存在闭环

在计算机中int所能存储的最大数字是2^31。这是一个十位数,拿最大的十位数来说,经过一次题目中所述的操作,结果就是:10*9^2=810。

也就是说,从0到2^31之间的所有数字经过一次操作后所得的结果一定在落在【1,810】这个区间之内,所以在0到2^31之间任意一个数经过811次操作后,每一次操作的结果一定都落在【1,810】区间内,而这个区间一共有810个整数,811次操作会得到811个整数,就一定可以推出至少有两次操作的结果是相等的!

这个原理就是鸽巢原理,意思就是有n个巢,n+1个鸽子,那么一定只少有一个巢中有两只鸽子!