leetcode
leetcode 151 ~ 200
快乐数

快乐数

难度:

标签:

题目描述

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

「快乐数」 定义为:

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

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

 

示例 1:

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

示例 2:

输入:n = 2
输出:false

 

提示:

  • 1 <= n <= 231 - 1

代码结果

运行时间: 19 ms, 内存: 16.1 MB


/*
 * The algorithm checks if a number is a happy number using Java Streams. 
 * A happy number is a number where the sum of the squares of its digits eventually equals 1. 
 * We use a HashSet to detect loops by storing numbers we've seen before. If we see a number twice, 
 * it means we're in a loop and the number is not happy.
 */
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;
 
public class HappyNumberStream {
    public boolean isHappy(int n) {
        Set<Integer> seen = new HashSet<>();
        while (n != 1 && !seen.contains(n)) {
            seen.add(n);
            n = Stream.of(String.valueOf(n).split(""))
                       .mapToInt(Integer::parseInt)
                       .map(x -> x * x)
                       .sum();
        }
        return n == 1;
    }
}

解释

方法:

该题解的思路是利用哈希集合检测循环。从给定的整数 n 开始,不断计算每一位上的平方和替换 n,直到 n 为 1 或者出现了之前计算过的 n,表示进入了循环。如果最后 n 等于 1,则是快乐数,否则不是。

时间复杂度:

O(logn * loglogn)

空间复杂度:

O(logn)

代码细节讲解

🦆
算法中使用列表记录出现过的数字,为何不使用哈希集合以提高查找效率?
使用列表来记录数字确实能工作,但查找效率相对较低,因为列表的查找时间是线性的。在这种情况下,使用哈希集合(例如 Python 中的 set)会更合适,因为哈希集合的平均查找时间为常数时间 O(1),这能显著提高算法的效率,尤其是当数字的范围较大或者循环链较长时。因此,替换列表为哈希集合是一个优化算法性能的好选择。
🦆
代码中提到如果 n 最终等于 1 则返回 true,但是在循环中是如何确保这个过程最终会停止而不是无限循环?
根据快乐数的定义,如果数字 n 不是快乐数,那么计算过程中生成的数字会开始重复,形成一个循环。这是因为整数的平方和的计算会最终达到一个有限的数值范围内。如果未达到 1 而开始循环,这表明我们已经遇到了之前计算过的数字,因此算法检查数字是否已在记录中出现,就可以判断是否进入了循环。一旦检测到循环,算法将停止并返回 false。这样,算法要么找到快乐数 1 并返回 true,要么发现循环并返回 false,因此算法总会停止。
🦆
在函数 `getSum` 中,你用除以 10 和取余操作来处理数字,这种操作对于处理非常大的数字是否仍然有效?
函数 `getSum` 中的除以 10 和取余操作用来分离出数字的每一位,并计算其平方和。这种方法不受数字大小的影响,对于非常大的数字同样有效。整数操作在计算机中是基本操作,可以处理任何大小的整数,只要它们在计算机内存和数据类型的表示范围内。在 Python 中,整数类型具有自动的大小扩展,可以处理非常大的数字而不会溢出。因此,这些操作对于任何大小的整数都是安全且有效的。

相关问题

环形链表

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false

 

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

 

提示:

  • 链表中节点的数目范围是 [0, 104]
  • -105 <= Node.val <= 105
  • pos-1 或者链表中的一个 有效索引

 

进阶:你能用 O(1)(即,常量)内存解决此问题吗?

各位相加

给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。返回这个结果。

 

示例 1:

输入: num = 38
输出: 2 
解释: 各位相加的过程为38 --> 3 + 8 --> 11
11 --> 1 + 1 --> 2
由于 2 是一位数,所以返回 2。

示例 2:

输入: num = 0
输出: 0

 

提示:

  • 0 <= num <= 231 - 1

 

进阶:你可以不使用循环或者递归,在 O(1) 时间复杂度内解决这个问题吗?

丑数

丑数 就是只包含质因数 235 的正整数。

给你一个整数 n ,请你判断 n 是否为 丑数 。如果是,返回 true ;否则,返回 false

 

示例 1:

输入:n = 6
输出:true
解释:6 = 2 × 3

示例 2:

输入:n = 1
输出:true
解释:1 没有质因数,因此它的全部质因数是 {2, 3, 5} 的空集。习惯上将其视作第一个丑数。

示例 3:

输入:n = 14
输出:false
解释:14 不是丑数,因为它包含了另外一个质因数 7 

 

提示:

  • -231 <= n <= 231 - 1