力扣每日一题之快乐数

1、题目描述

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

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

如果 n 是快乐数就返回 True ;不是,则返回 False 。

2、示例

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

3、算法分析

(当时没想到双指针,陷入循环无法break。阅读题解后,我只想说喵啊~)题解戳这里->https://leetcode-cn.com/problems/happy-number/solution/shi-yong-kuai-man-zhi-zhen-si-xiang-zhao-chu-xun-h/
第 1 部分我们按照题目的要求做数位分离,求平方和。

第 2 部分按照一系列的数字来判断我们是否进入了一个循环。

存在两种情况:

  • 收敛于1

力扣每日一题之快乐数_第1张图片

  • 陷入循环

力扣每日一题之快乐数_第2张图片

通过反复调用getnum(n)得到的是一个隐式链表。隐式意味着我们没有实际的链表节点和指针,但数据仍然形成链表结构。起始数字是链表的头 “节点”,链中的所有其他数字都是节点。next 指针是通过调用 getnum(n) 函数获得。

意识到我们实际有个链表,那么这个问题就可以转换为检测一个链表是否有环。因此我们在这里可以使用弗洛伊德循环查找算法。这个算法是两个奔跑选手,一个跑的快,一个跑得慢。在龟兔赛跑的寓言中,跑的快的称为 “乌龟”,跑得快的称为 “兔子”。

不管乌龟和兔子在循环中从哪里开始,它们最终都会相遇。这是因为兔子每走一步就向乌龟靠近一个节点(在它们的移动方向上)。

如下图所示:

力扣每日一题之快乐数_第3张图片

我们不是只跟踪链表中的一个值,而是跟踪两个值,称为快跑者和慢跑者。在算法的每一步中,慢速在链表中前进 1 个节点,快跑者前进 2 个节点(对 getnum(n) 函数的嵌套调用)。

如果 n 是一个快乐数,即没有循环,那么快跑者最终会比慢跑者先到达数字 1。

如果 n 不是一个快乐的数字,那么最终快跑者和慢跑者将在同一个数字上相遇。

4.代码如下:

public class HappyNum {
    public static boolean isHappy(int n) {
        int slow = n, fast;
        slow = getsum(slow);
        fast = getsum(slow);
        while (fast != 1 && slow != fast) {
            slow = getsum(slow);
            fast = getsum(getsum(fast));
        }
        return fast == 1;
    }

    /**
     * 获取下一个各个位数平方和的结果
     *
     * @param n
     * @return
     */
    private static int getsum(int n) {
        int sum = 0;
        while (n > 0) {
            int temp = n % 10;
            n /= 10;
            sum += temp * temp;
        }
        return sum;
    }

    public static void main(String[] args) {
        System.out.println(isHappy(20));
    }
}

想要阅读更多博客请点击这里查看–>https://lisongbai.top/

你可能感兴趣的:(leetcode每日一题)