题目:
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
第一步:需要将每一位的数字单独拿出来求平方
整数最大为10位数,但用1000000000*10之后就无法运行,所以会报错,那么添加一个计数器k,最终k为11但终止循环,导致m不会再增加。
bool isHappy(int n){
n = 375231;
int r = 0;
int m = 1;
for (int k = 1; k <= 10; k++){
int d = n / m % 10;//d: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
//m: 1, 10, 100, ..., 1000000000
//k: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
printf("%d\n",d);
r += d * d;
if (k < 10){
m *= 10;
}
}
return false;
}
另一种想法是倒过来做,这样输出的位数是从高位到低位
bool isHappy(int n){
int r = 0;
int m = 1;
for (int m = 1000000000; m >= 1; m /= 10){
int d = n / m % 10;
r += d * d;
}
}
printf("%d\n",r);
return false;
}
简化写法(不断将原本的数字/10)
bool isHappy(int n){
int r = 0;
while (n != 0){
int d = n % 10;
n /= 10;
r += d * d;
}
printf("%d\n",r);
return false;
}
第二步:对其进行循环
int next_n(n){
int r = 0;
while (n != 0){
int d = n % 10;
n /= 10;
r += d * d;
}
return r;
}
bool isHappy(int n){
printf("%d\n",next_n(n));
return false;
}
我们需要知道,程序做到什么时候才停止,检查数字n是否出现过,当他没有出现过,一直走,当n再次出现时有两种情况,①n为1,此事是happy number ②n不会1,则为false。
int next_n(n){ //回传下一次的n
int r = 0;
while (n != 0){
int d = n % 10;
n /= 10;
r += d * d;
}
return r;
}
bool contain(int* history, int size, int n){ //检查 n 是否在 history 中出现过
for (int i =0; i < size; i++){
if (history[i] == n){
return true;
}
}
return false; //false的意思就是它没有出现过
}
bool isHappy(int n){
int history[10000]; // 我们去过哪里
int size = 0; //总共有几个地方
//history = [?,?,?,?,?,?]
//size = 0
// n = 19
while (!contain(history, size, n)){
history[size] = n; //histort[0]=19
size++;
n = next_n(n); // n : 82
}
return n == 1;
}
疑问:有没有可能产生的新的数字超过一万个?
想想如果有10位数,每位数均为最大,9999999999 ==》 9 * 9 * 10 =810
他运算的数字最大为810
我们可以在循环前第一次先无条件走一步,此时次数最多就只有810种不一样。
但是确定空间大小仍是不确定的,所以可以让其变循环,空间逐渐长大
龟兔赛跑算法(Floyd’s Tortois and Here)
一开始都在起点,乌龟一次走一步,兔子一次走两步,兔子会从尾巴上追上乌龟并且撞在一起,此时便说明会有循环发生,对于此题,我们需要检查当两者撞在一起时是否为1即可。
双指标方法:
int next_n(n){ //回传下一次的n
int r = 0;
while (n != 0){
int d = n % 10;
n /= 10;
r += d * d;
}
return r;
}
bool isHappy(int n){
int slow = n;
int fast = n;
do{ //一开始两个是在一起的
slow = next_n(slow); //乌龟走一步
fast = next_n(next_n(fast));//兔子走两步
} while (slow != fast); //走完之后就要检查两个是否撞在一起,当不一样时,继续做
return fast == 1; // 检查乌龟和兔子都可以
}
不需要额外的阵列占用空间。
class Solution:
def getNext(self, n: int) -> int:
next_n = 0
while(n != 0):
next_n += (n % 10) ** 2
n = n // 10
return next_n
def isHappy(self, n: int) -> bool:
slow = n
fast = self.getNext(n)
while(fast != 1 and slow != fast):
slow = self.getNext(slow)
fast = self.getNext(self.getNext(fast))
return fast == 1
作者:coldme-2
链接:https://leetcode-cn.com/problems/happy-number/solution/hashsetshuang-zhi-zhen-python-by-coldme-2/