双指针(3)_快慢指针_快乐数问题

个人主页:C++忠实粉丝
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C++忠实粉丝 原创

双指针(3)_快慢指针_快乐数问题

收录于专栏【经典算法练习
本专栏旨在分享学习C++的一点学习笔记,欢迎大家在评论区交流讨论💌

目录

1.题目链接:

2.题目描述:

3.解法:

算法思路:

算法流程:

代码展示:

结果分析:

4.总结:


 

1.题目链接:

202. 快乐数 - 力扣(LeetCode)

2.题目描述:

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

示例 1:

输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

示例 2:

输入:n = 2
输出:false

提示:

  • 1 <= n <= 231 - 1

3.题目分析:

为了方便叙述,将「对于⼀个正整数,每⼀次将该数替换为它每个位置上的数字的平方和」这一个操作记为x

题目告诉我们,当我们不断重复 x 操作的时候,计算一定会「死循环」,死的方式有两种:

        ▪ 情况一:一直在 1 中死循环,即 1 -> 1 -> 1 -> 1......

        ▪ 情况二:在历史的数据中死循环,但始终变不到 1

由于上述两种情况只会出现一种,因此,只要我们能确定循环是在「情况一」中进行,还是在「情况二」中进行,就能得到结果。

示例一:

示例二: 

简单证明: 

a. 经过一次变化之后的最大值是: 9^2 * 10 = 810 ,也就是在题目要求变化的区间 [1, 2^31-1=2147483647] ,选一个更大的最大( 999999999 ), 也就是变化区间在[1, 810] 之间;

b. 根据「鸽巢原理」(n个巢,n+1个鸽,至少有一个巢里面的鸽子数大于1),一个数变化 811 次之后,必然会形成⼀个循环;

c. 因此,变化的过程最终会走到⼀个圈里面,因此可以用「快慢指针」来解决。

4.解法:

算法思路:

根据上述的题目分析,我们可以知道,当重复执行 x 的时候,数据会陷入到一个「循环」之中。 而「快慢指针」有一个特性,就是在一个圆圈中,快指针总是会追上慢指针的,也就是说他们总会相遇在一个位置上。如果相遇位置的值是 1 ,那么这个数一定是快乐数;如果相遇位置不是 1 的话,那么就不是快乐数。

证明为什么两个快慢指针一定会相遇?两个快慢指针为什么相遇点是入环的起始点?

这个我就不过多证明,详细证明大家可以看下面的博客,里面关于链表的带环问题进行了详细的分析与证明:

链表经典面试题02--链表的带环问题-CSDN博客

算法流程:

1. 单独实现将每个数的位数进行平方求和的函数(因为在题目中会多次使用)

2. 定义两个快慢指针slow和fast

3. 当我们的slow != fast时,说明slow还没与fast相遇,那么slow++,fast += 2;

    当我们的slow == fast时,说明slow与fast相遇,且相遇点是入环起始点,那么我们只需要判断这个点的值是否为1,为1则为快乐数,否则不是.

注意:我们的循环判断条件为slow != fast,那么我们两个指针初始化时,不能同时初始化为n,应该将slow = n, fast = n各个位数的平方和;

代码展示:

class Solution {
public:
    int numsum(int n)
    {
        int sum = 0;
        while(n)
        {
            int x = n % 10;
            sum += x * x;
            n /= 10;
        }
        return sum;
    }

    bool isHappy(int n) {
        int slow = n, fast = numsum(n);
        while(slow != fast)
        {
            slow = numsum(slow);
            fast = numsum(numsum(fast));
        }
        if(slow == 1) return true;
        else return false;
    }
};

结果分析:

顺利通过!!! 

4.总结:

这道题考察了双指针算法中的快慢指针,快慢指针在平常算法中还算比较常见,希望大家可以通过这道题掌握这种算法,如果大家还想练习的话,可以参考下面的博客--有关链表的带环问题,进行加深练习!!!

链表经典面试题02--链表的带环问题-CSDN博客

对了,如果这篇博客对你有帮助的话,不要忘记赞👍 收藏✨ 留言✉ 加关注💓哦!!
大家也可以订阅我的经典算法专辑[经典算法练习],每天都会更新一道经典算法(正常来说),让你遇到算法不在害怕!!!

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值