【LeetCode - Java】202. 快乐数 (简单)

目录

1. 题目描述

【LeetCode - Java】202. 快乐数 (简单)

2. 解题思路

这道题目的逻辑是很简单的,难点是在于如何判断已经循环够了,该跳出循环了?首先,如果这个数是快乐数,最终会等于1,那么就可以直接跳出循环并返回了;但是,如果这个数不是快乐数,他就会无限循环,那还有什么规律吗?我发现,对于10以下的数,只有1和7是快乐数,其他都不是,那么这就意味着当我迭代发现当前数是小于10并且不是71时,就该结束循环返回false了,这种解法我称之为规律法,可能并不是十分正统的思路。

那么有其他正统的思路吗?如果我能记住我之前判断过什么数字,当我又重新遇到这个数字的时候,那不就代表着存在死循环,可以返回false了。实现方法自然而然就想到了哈希表

既然说遇到某个数字会产生死循环,那么是不是特定的几个数字呢?我手写推算了几位数字发现,对于非快乐数而言最终都会掉进4, 16, 37, 58, 89, 145, 42, 20这个循环当中,那就意味着只要在迭代过程中的数是以上之一,那么他就不是快乐数了,这是基于记忆(哈希表)和规律的思路。

循环,相当于一个链表中拥有回路,在【LeetCode - Java】141. 环形链表 (简单)中介绍过一种高效的快慢指针算法,可以快速地进行判断,对于这一道题目是同样适用的。

3. 代码实现

3.1 规律法

public boolean isHappy(int n) {
        int sum;
        while (n != 1) {
            if (n < 10 && n != 7)
                return false;
            sum = 0;
            while (n != 0) {
                sum += (int) Math.pow(n % 10, 2);
                n /= 10;
            }
            n = sum;
        }
        return true;
    }

3.2 哈希表

public boolean isHappy(int n) {
        HashSet<Integer> set = new HashSet<>();
        int sum;
        while (!set.contains(n)) {
            set.add(n);
            sum = 0;
            while (n != 0) {
                sum += Math.pow(n % 10, 2);
                n /= 10;
            }
            if (sum == 1)
                return true;
            n = sum;
        }
        return false;
    }

3.3 哈希表+规律

public boolean isHappy(int n) {
        HashSet<Integer> set = new HashSet<>(Arrays.asList(4, 16, 37, 58, 89, 145, 42, 20));
        while (!set.contains(n)) {
            if (n == 1)
                return true;
            int sum = 0;
            while (n != 0) {
                sum += Math.pow(n % 10, 2);
                n /= 10;
            }
            n = sum;
        }
        return false;
    }

3.4 快慢指针

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

    public int next(int n) {
        int sum = 0;
        while (n != 0) {
//            sum += Math.pow(n % 10, 2);
            sum += (n % 10) * (n % 10);
            n /= 10;
        }
        return sum;
    }

3.5 对比

理论上,上述所有方法的时间复杂度都是线性复杂度,因此时间差异都不大,哈希表的时间消耗较大应该是哈希表的存储查询导致的。另外,一个很有意思的点是在快慢指针算法当中,我尝试自己使用乘法进行平方运算,结果发现比使用Math.pow函数内存消耗更低
【LeetCode - Java】202. 快乐数 (简单)

上一篇:1.1 GUI编程


下一篇:剑指 Offer 05. 替换空格(字符串 双指针法)(Leetcode刷题笔记)