Leetcode【快慢指针 链表找环思想】| 202. 快乐数

题目

编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
示例:
 输入:19
 输出:true
解释:
 12 + 92 = 82
 82 + 22 = 68
 62 + 82 = 100
 12 + 02 + 02 = 1
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/happy-number

解题

思路

 首先,我们需要注意到这个快乐数的寻找过程,其实是一个循环。那么我们就可以将这个问题转变为链表找环问题。
为什么会是一个循环,我们单纯来思考找快乐数的这一过程:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。这样我们的寻找过程会有三种情况:

  1. 寻找过程为:n -> n1 -> n2 -> … -> ni -> 1 -> 1… 这种情况是快乐数,最后变成1的循环。如题中示例19 -> 82 -> 68 -> 100 -> 1 -> 1 -> …
  2. 如果不是快乐数,这个数字的寻找过程可能会变成这样的一种循环: n -> n1 -> n2 -> … -> ni -> … -> nj-> ni -> … -> nj… 如下图例(图源于力扣官方题解
    在这里插入图片描述
  3. 也可能会变成越来越大的情况。
    但经过证明可以发现不会出现越来越大的情况呢?可以看甜姨题解里给出的证明。或者可以这样想,当每位数都为最大时,他的平方和为多少,比如十三位数的最大值9999999999999的每位数平方和为1053,我们可以得出对于一个十三位数其最坏情况也会将其降低至四位数1053最终很可能在四位数之内进行循环,所以其实到最大的时候都会急速下降使其在某个范围内循环不会出现会越来越大的情况。
    所以这个问题就变成了必然会形成一个环,找环的入口问题,如果最终环的入口为1那么为快乐数,环的入口不为1就不是快乐数。

想清楚这个问题,这道题的解题思路就和Leetcode | 141. 环形链表的找环思路一模一样了。
唯一不同的就是环形链表的下一个直接用node.next就可以找到,这道题的下一个需要写一个计算其每位数平方和的方法去找其下一个。

快慢指针找环解法(java)

参考甜姨题解

public class Solution {
    //计算每一次将该数替换为它每个位置上的数字的平方和的过程
    public int squareSum(int n) {
        int sum = 0;
        while(n > 0){
            //依次整除10将个位数提取出来,依次加上平方和,算出每位数的平方和的总和
            int digit = n % 10;
            sum += digit * digit;
            n /= 10;
        }
        return sum;
    }

    public boolean isHappy(int n) {
        //设置快慢指针,fast每次平方两步,slow每次平方一步,找到是否存在环的相遇点,因为不会无限放大
        int slow = n, fast = squareSum(n);
        while (slow != fast){
            slow = squareSum(slow);
            fast = squareSum(squareSum(fast));
        };
        return slow == 1;//环的相遇点是1的说明最终会变为快乐数
    }
}

在这里插入图片描述

哈希表解法

public class Solution {
    //计算每一次将该数替换为它每个位置上的数字的平方和的过程
    public int squareSum(int n) {
        int sum = 0;
        while(n > 0){
            //依次整除10将个位数提取出来,依次加上平方和,算出每位数的平方和的总和
            int digit = n % 10;
            sum += digit * digit;
            n /= 10;
        }
        return sum;
    }

    public boolean isHappy(int n) {
        //设置一个哈希表,存储每次的数,遇到重复的说明是环的入口
        Set<Integer> numset = new HashSet<>();
        while(!numset.contains(n)&&n!=1){
            numset.add(n);
            n = squareSum(n);
        }
        //判断环的入口是否为1
        return n == 1;//环的相遇点是1的说明最终会变为快乐数
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值