1-3 LC202 快乐数 C++ Java力扣刷题笔记 快慢指针法!要理解透彻!!

本文通过LC202快乐数问题,讲解了如何利用哈希集合和快慢指针法判断一个数是否为快乐数。详细分析了两种思路的逻辑,并提供了C++和Java的实现代码,讨论了避免哈希集合过大和处理循环问题的方法。
摘要由CSDN通过智能技术生成

LC202 快乐数

在这里插入图片描述
LC202

1.读题

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

快乐数的定义——

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

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

在这里插入图片描述

2.题解

【1】解题思路

思路一 哈希集合检测循环

本题中我们需要一步一步地判断是否平方和为1 且 需要一边判断一边查重~

怎么样 是不是自然而然地想到了链表 想到了“哈希集合” ~

来看看官方题解的方法一——
利用哈希集合检测循环
在这里插入图片描述
总结一下 最终的平方和的结果可能性——

1.最终得到1
2.最终进入循环 被查重
3.平方和越来越大 最后接近无穷大

其中最难检测和处理的就是第三种情况。。
代码中到底要不要管第三种情况呢??
我们单独把第三部分拎出来说道说道

如何判断平方和的最终值是否接近无穷大

依旧是参考官方题解的解释——
【1】思考一下 n位最大数的平方和为多少?
在这里插入图片描述
【2】这就很有意思了!
可以看到 是三位数的巅峰——999 取每一位的平方和之后得到的值不增反减
这意味着 三位数的数字是不可能大于243的
【3】在不断求每位数字的平方和的过程中
这个数——
要不就跌倒1
要不就在1-243之间循环
这个过程不会是无限的!他总会回到一个数!
【4】综上所述 第三种情况是永远不会发生的!
直接排除hhh

思路二 快慢指针法

快慢指针 解决循环问题yyds!!!!!
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
利用快慢指针思想找出循环是万能方法!

其实思想1和思想2大致的思想都是差不多的
都是判断n是否为1或者n是否是遍历过的节点 然后得到是否为快乐数
区别在于思想二利用快慢指针找到“遍历过的节点” 不用集合记录每次的计算结果 规避了集合超大到无法存储的情况(如果给出的n不是整数型就gg了鸭)

  • 第一步
    在这里插入图片描述

省略n步

  • 最后一步 快指针和慢指针重合
    在这里插入图片描述
    判定链表中存在循环~
    非快乐数!!!

【2】代码逻辑

思路一

经过上面的分析 我们得知 分两种情况就OK了~

最终结果为1
最终被查重

开始写代码!
1.获得“各位置数字平方之和”的函数getNext()的完成
【1】利用一个while循环就OK啦~
在这里插入图片描述
【2】最后别忘了返回最终结果val

这里真的是梦回大一程序设计与基础hhh

2.判断输入的n是否为快乐数的函数isHappy()
【1】先创建一个集合并进行初始化
【2】进入while循环 直到 确定n为快乐数/不是快乐数 为止
【3】循环中不断进行不符合节点插入哈希表&计算各位置数字平方之和的操作
【4】跳出while循环 最终返回 n==1
【5】bool型函数 isHappy会给你答案~

True 或者 False

思路二

1.部分是完全相同的
2.部分使用了快慢指针的思想

回头一定要多复现几次这种思想! 涉及到循环的题都能用!

我们跟踪链表中的两个值
算法的每一步 慢数在链表中前进一个节点 快数前进两个节点

【1】初始化快慢数为输入数
【2】循环中 慢数变化一次 快数变化两次
【3】如果n为快乐数 那么没有循环 快数会比慢数先到达数字1
【3’】n不是快乐数 有循环 那么快数将和慢数在链表中的同一个数字上相遇

这样做 可以解决哈希集合过大的问题! 会节约很多内存!

3.C++代码

思路一

这注释的量都快比代码多辽
能看得懂8~

class Solution {
public:
    int getNext(int n){
        int val = 0;
        while(n != 0)//其实while(n)就ok 这样写清晰点hh——当n不为0的时候 一直进行平方和的求和
        {
            int middle = n % 10;//每一位的那个数字
            val += middle * middle;
            n /= 10;
        }
        return val;//返回计算得到的“各位置数字平方之和”
    }

    bool isHappy(int n) {
        unordered_set<int> record; //创建集合容器unordered_set 即为哈希表 命名为record 
        while(n!=1 && !record.count(n)) { //n不等于1 且 没有查重成功(record.count(n)不等于1)就一直循环
            record.insert(n); //向哈希表中加入遍历到的这个节点
            n = getNext(n);
        }
        return n == 1;//满足其中一项条件(是快乐数 / 不是快乐数) 退出循环 
        //如果最终的n为1的话 布尔型函数isHappy(n == 1)将返回 True
        //如果最终的n只是因为查重成功退出 布尔型函数isHappy将返回 False
    }
    
};

在这里插入图片描述

思路二

class Solution {
public:
    int getNext(int n){
        int val = 0;
        while(n != 0)//其实while(n)就ok 这样写清晰点hh——当n不为0的时候 一直进行平方和的求和
        {
            int middle = n % 10;//每一位的那个数字
            val += middle * middle;
            n /= 10;
        }
        return val;//返回计算得到的“各位置数字平方之和”
    }

    bool isHappy(int n) {
        int slow = n, fast = n;
        do {
            slow = getNext(slow);
            fast = getNext(fast);
            fast = getNext(fast);
        }
        while (slow != fast);//快指针没追上慢指针之前 一直重复计算各位置数字平方之和

        return slow == 1;
    }

    
};

可以看到内存消耗是大大减少的~

在这里插入图片描述

4.Java代码

思路一

class Solution {
    private int getNext(int n) {
        int val = 0;
        while(n > 0) {
            int x  = n % 10;
            val += x*x;
            n /= 10;
        }
        return val;
    }
    public boolean isHappy(int n) {
        Set<Integer> seen = new HashSet<>();
        while (n != 1 && !seen.contains(n))//n不等于1 且 没有查重成功(seen.contains(n)不等于1)就一直循环
        {
            seen.add(n);
            n = getNext(n);
        }
        return n == 1;
    }
}

在这里插入图片描述

思路二


class Solution {

     public int getNext(int n) {
        int totalSum = 0;
        while (n > 0) {
            int d = n % 10;
            n = n / 10;
            totalSum += d * d;
        }
        return totalSum;
    }

    public boolean isHappy(int n) {
        int slowRunner = n;
        int fastRunner = getNext(n);
        while (fastRunner != 1 && slowRunner != fastRunner) {
            slowRunner = getNext(slowRunner);
            fastRunner = getNext(getNext(fastRunner));
        }
        return fastRunner == 1;
    }
}


依旧是明显提升的性能呢!
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值