Skip to content

202.快乐数

难度:简单

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

「快乐数」 定义为:

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

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

示例 1:

输入:n = 19
输出:true
解释:
1^(2) + 9^(2) = 82
8^(2) + 2^(2) = 68
6^(2) + 8^(2) = 100
1^(2) + 0^(2) + 0^(2) = 1

示例 2:

输入:n = 2
输出:false

提示:

  • 1 <= n <= 2^(31) - 1

解题思路

使用哈希集合,来判断这个 求和的结果 是否重复出现,如果重复了就是返回 false, 否则就一直找,直到求和的结果为 1

还有一个难点就是求和的过程,需要熟悉取一个数各个位上的值的操作

我的代码(哈希集合)

java
public boolean isHappy(int n) {
    // 使用HashSet来记录所有出现过的数字
    Set<Integer> record = new HashSet<>();
    // 当n不为1且n没有在之前出现过
    while (n != 1 && !record.contains(n)) {
        record.add(n);
        int res = 0;
        // 计算n的每一位数字的平方和
        while (n > 0) {
            int temp = n % 10;// 获取n的最后一位数字
            res += temp * temp;// 计算这个数字的平方并加到res中
            n /= 10;// 移除n的最后一位数字
        }
        n = res;// 更新n为其每位数的平方和
    }
    // 如果循环结束时n为1,则是快乐数,否则不是
    return n == 1;
}

时间复杂度: O(logn)

空间复杂度: O(logn)

快慢指针法

思路概述

上述算法中,通过反复对 res 进行求值,我们得到了 record 哈希集合,如果令此集合有序的话,不难看出此集合是一个隐式的链表。

隐式意味着我们虽然没有实际的链表节点和指针,但数据仍然形成了链表结构。

那么这个问题就转换为了:检测一个链表是否有环

因此我们在这里可以使用 快慢指针法

仿照 142 题的做法,我们使用两个指针,慢指针每步走一个节点,快指针每步走两个节点。

如果 n 是一个快乐数,说明链表无环,那么两个指针只存在一种相遇的情况:两个指针最后都指向数字 1,且一直停留在 1。

如果 n 不是一个快乐数,说明链表有环,那么当两个指针无论何时相遇,两个指针都不会指向 1。

代码展示

java
public boolean isHappy(int n) {
    // 使用快慢指针检测数字序列中的循环
    int slow = n;
    int fast = getNext(n);
    while (slow != fast) {
        slow = getNext(slow); // 慢指针每次移动一步
        fast = getNext(getNext(fast)); // 快指针每次移动两步
    }
    // 如果快指针到达1,则为快乐数
    return fast == 1;
}

public int getNext(int n) {
    int res = 0;
    while (n > 0) {
        int temp = n % 10;
        res += temp * temp; // 计算每位数字的平方和
        n /= 10;
    }
    return res;
}

时间复杂度: O(logn)

空间复杂度: O(1)

总结

遇到环形链表问题就使用快慢指针法,要形成一种条件反射。