算法双指针系列-Day2-快乐数


前言

快慢指针:又称为龟兔赛跑算法,其基本思想就是使用两个移动速度不同的指针在数组或链表等序列结构上移动。
这种方法对于处理环形链表或数组非常有用。
其实不单单是环形链表或者是数组,如果我们要研究的问题出现循环往复的情况时,均可考虑使用快慢指针的思想。
快慢指针的实现方式有很多种,最常用的一种就是:
• 在一次循环中,每次让慢的指针向后移动一位,而快的指针往后移动两位,实现一快一慢。


一、题目链接

快乐数

二、题目描述

在这里插入图片描述

三、算法思路

1.初步分析

读题可知,如果将一个数字替换成它每个位置上数字的平方和,然后一直重复此操作,如果这个数最后变成了1,那这个数就是快乐数,如果死循环了,那就不是快乐数。本质上都是死循环,区别是前者死循环里全是1,后者死循环里全不是1,题目已经明确告知只有这两种情况。下面举两个例子,一个是以1死循环,另一个也是死循环,但里面没有1.
在这里插入图片描述
在这里插入图片描述
相信看图就很容易理解了。
疑问
但这里我还有个问题,题目中是已经告诉了我们不管是不是快乐数都会进入死循环,那如果题目中没有告诉我们这个条件呢?所以有没有可能有一种情况是他是无限的,没有进入循环呢?答案是没有,下面我将证明这个结论,当然这个并不影响做题,大家可以选择跳过。
我想先举个例子是我们小学学过的内容,名字叫鸽巢原理,简单来说就是有n个巢,但有n+1只鸟,结论是至少有一个巢有两只或两只以上的鸽子。这个题目呢和鸽巢原理类似。
在这里插入图片描述
规定n的范围是这么大,我们用计算机算一下。发现最大也就十位数嘛,假设十位数,每一位数字都是9,那10个9的平方也才81*10=810而已嘛。那如果我算欢乐数算811次,即使前810次全不相同,那第811次就一定和之前的一次重复了吧,所以它最后肯定是一个死循环。是不是和鸽巢原理很类似呢?
在这里插入图片描述

2.更进一步

有了上面的分析,我们可以知道确定是不是欢乐数的关键就是确定它是哪一种死循环嘛。这里我们就可以使用快慢双指针法来解决这个问题,快慢指针有一个特性,就是在一个圆圈中,快指针总是会追上慢指针的,也就是说他们总会
相遇在一个位置上。如果相遇位置的值是 1 ,那么这个数一定是快乐数;如果相遇位置不是 1那就不是快乐数。

3.代码编写

我们先写一个函数叫bitSum用来返回 n 这个数每⼀位上的平⽅和,具体实现:
迭代以下步骤
i. int t = n % 10 提取个位;
ii. n /= 10 干掉个位;
直到 n 的值变为 0 ;
代码实现:

int bitSum(int n) // 返回 n 这个数每⼀位上的平⽅和
    {
        int sum = 0;
        while (n) {
            int t = n % 10;
            sum += t * t;
            n /= 10;
        }
        return sum;
    }

然后设置一个快指针一个慢指针,快指针每次算两次快乐数,慢指针每次算一次快乐数,由上述分析可得快指针和慢指针最后一定会相遇,即相等。所以判断最后的指针是不是等于1就可以判断是不是快乐数,如果是1则是,否则不是。
代码:

bool isHappy(int n) {
        int last, fast;
        last = n;
        fast = bitSum(n);
        while (fast != last) {
            last = bitSum(last);
            fast = bitSum(bitSum(fast));
        }
        return last == 1;
    }

C++整体代码:

class Solution {
public:
    int bitSum(int n) // 返回 n 这个数每⼀位上的平⽅和
    {
        int sum = 0;
        while (n) {
            int t = n % 10;
            sum += t * t;
            n /= 10;
        }
        return sum;
    }
    bool isHappy(int n) {
        int last, fast;
        last = n;
        fast = bitSum(n);
        while (fast != last) {
            last = bitSum(last);
            fast = bitSum(bitSum(fast));
        }
        return last == 1;
    }
};

运行结果:
在这里插入图片描述
Java完整代码:

class Solution {
    public int bitSum(int n) // 返回 n 这个数每⼀位上的平⽅和
    {
        int sum = 0;
        while (n != 0)

        {
            int t = n % 10;
            sum += t * t;
            n /= 10;
        }
        return sum;
    }

    public boolean isHappy(int n) {
        int slow = n, fast = bitSum(n);
        while (slow != fast) {
            slow = bitSum(slow);
            fast = bitSum(bitSum(fast));
        }
        return slow == 1;
    }
}

运行结果:
在这里插入图片描述

  • 17
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

争不过朝夕,又念着往昔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值