题目
编写一个算法来判断一个正整数 n 是不是快乐数,如果 n 是快乐数就返回 true,否则返回 false 。如下所示,19为快乐数。
输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
如下图所示,116不是快乐数:
解决思路
- 快乐数定义
(1) 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
(2) 然后重复这个过程直到这个数变为 1,也可能是无限循环但始终变不到 1。
(3) 如果结果可以变为1,那么这个数就是快乐数,如果不能变为1,则不是快乐数。 - 思路
(1)快乐数对应单链表无环的情况,不是快乐数对应单链表有环的情况。
(2)使用快慢指针追逐法判断链表是否有环的思想解决此题(参考这里)。
(3)将正整数 n 分解的过程看做一个单链表,如果 n 是快乐数,则分解过程中最后一个值为1,用end表示该节点,可将该节点看做链表中的null。
(4)如果 n 是快乐数,则链表无环,也即快慢指针不能相遇,快指针最终会指向null(上述的end节点)或null的上一个节点。
(5)如果 n 不是快乐数,即 n 的分解过程最终得不到1,可以理解为无限分解下去都走不到end节点。此种情况对单应链表中有环的情况(无限循环最终都不能指向null)。
代码
- C++代码
# include <stdio.h>
class Solution {
public:
int getNext(int n) {
if (1 == n || 0 == n) {
return n;
}
int sum = 0;
while (n) {
sum += (n % 10) * (n % 10);
n /= 10;
}
return sum;
}
bool isHappy(int n) {
if (1 == n) {
return true;
}
int slow = n; // 模拟慢指针
int quick = n; // 模拟快指针
do {
slow = getNext(slow); // 慢指针每次走1步
quick = getNext(getNext(quick)); // 快指针每次走2步
} while (slow != quick && quick != 1 && getNext(quick));
return quick == 1 || getNext(quick) == 1;
}
};
int main() {
int test = 19;
Solution *solution = new Solution();
if (solution->isHappy(test)) {
printf("is a happy num\n");
} else {
printf("is not a happy num\n");
}
return 0;
}
- python代码
- 代码1:
# -*- coding: utf-8 -*-
import math
# 方法1:开始时刻,快慢指针都指向头结点。运算过程中使用math.floor求商
class Solution:
def getNext(self, n):
if 1 == n or 0 == n:
return n
sum = 0
while n:
sum += (n % 10) * (n % 10)
n = math.floor(n / 10)
return sum
def isHappy(self, n: int) -> bool:
if 1 == n:
return True
slow, quick = n, n
slow = self.getNext(slow)
quick = self.getNext(self.getNext(quick))
while slow != quick and quick != 1 and self.getNext(quick) != 1:
slow = self.getNext(slow)
quick = self.getNext(self.getNext(quick))
return 1 == quick or 1 == self.getNext(quick)
def main():
test = 19
solution = Solution()
if solution.isHappy(test):
print('is a happy num')
else:
print('is not a happy num')
if __name__ == "__main__":
main()
- 代码2:
# -*- coding: utf-8 -*-
# 方法2:开始时刻,慢指针指向头节点,快指针指向头结点的下一个节点。运算过程中使用divmod求余
class Solution:
def getNext(self, n):
if 1 == n or 0 == n:
return n
sum = 0
while n:
n, a = divmod(n, 10)
sum += a ** 2
return sum
def isHappy(self, n: int) -> bool:
if 1 == n:
return True
slow, quick = n, self.getNext(n)
while slow != quick and quick != 1 and self.getNext(quick) != 1:
slow = self.getNext(slow)
quick = self.getNext(self.getNext(quick))
return 1 == quick or 1 == self.getNext(quick)
def main():
test = 19
solution = Solution()
if solution.isHappy(test):
print('is a happy num')
else:
print('is not a happy num')
if __name__ == "__main__":
main()
python两种方法的区别:
(1)开始时刻快慢指针的位置不同,方法1中开始时刻快慢指针都指向头节点(链表的第一个节点)。方法2中,开始时刻慢指针指向头节点,快指针指向头节点的下一个节点。
(2)方法1中求商时,使用了math.floor向下取整。注意,若不进行向下取整,商可能为小数,导致结果错误。
(3)方法2中使用了divmod求商和余数,推荐使用该方法。
说明
- 对应LeetCode第202题。
- 链接:https://leetcode-cn.com/problems/happy-number/