我把题目复制到这里来~
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
示例:
输入:19
输出:true
解释:
1^2 + 9^2 = 82
8^2 + 2^2 = 68
6^2 + 8^2 = 100
1^2 + 0^2 + 0^2 = 1
今天一直在看Vue…于是又来睡前用LeetCode水博客了…
可以直接跳到下面的大佬方法。我的方法不够帅。
n.toString().split(""); // 返回数组,如n=1234,则返回['1','2','3','4']
let sum=0;
arr.forEach((num)=>{
sum += num*num;
});
// forEach结束后的sum就是新的数字了
let sum=0;
for(let i of n.toString()){
sum+=i*i;
}
但是难点主要在于,如果他不是快乐数,如何界定这个终止的点。不是快乐数的情况下直接用while true的话肯定会导致死循环。这种时候就很尴尬,肯定要换个思路,怎么判断他不是快乐数。
其实思路很简单,只要这个数字在遍历的过程中值成为1之前重复了,他就一定不是快乐数。为什么?因为快乐数最终导向一定是1,而重复了的数字一定会再次重复,他就一定不会到1。
掏出我的答案
var isHappy = function (n) {
let sumArr = [];
let numStr = n.toString();
while (true) {
// 每位平方的和
let sum = 0;
for (let i of numStr) {
sum += i * i;
}
console.log(sum);
// 如果是1
if (sum === 1) {
return true;
}
// 数字是否重复
if (sumArr.includes(sum)) {
// 重复了说明不快乐
return false;
} else {
// 还没重复就加入记录
sumArr.push(sum);
// 将之前的sum存一下
numStr = sum.toString();
}
}
};
做是做出来了,但是呢:
执行用时 :152 ms, 在所有 JavaScript 提交中击败了5.28%的用户
内存消耗 :39.8 MB, 在所有 JavaScript 提交中击败了20.00%的用户
首先用set代替array,具体查看这篇文章-使用 JavaScript 的 Set 集合提升你代码的性能
代码是酱紫的
// 定义
let sumSet = new Set();
// 循环里面添加
sumSet.add(sum);
然后return false可以移动到外面,这样每次循环少进行一次判断。代码是酱紫的
// return false移动到外面
while(!sumSet.has(n)){
...
}
return false;
去掉numStr,直接用n存储,减少空间占用
let sumSet = new Set();
// let numStr = n.toString(); 删掉
while (!sumSet.has(n)) {
// 每位平方的和
let sum = 0;
for (let i of n.toString()) {
sum += i * i;
}
console.log(sum);
// 如果是1
if (sum === 1) {
return true;
}
// 加入记录
sumSet.add(n);
// numStr = sum.toString();删掉
n = sum; //新增
}
return false;
执行用时 :84 ms, 在所有 JavaScript 提交中击败了34.62%的用户
内存消耗 :35.8 MB, 在所有 JavaScript 提交中击败了20.00%的用户
剪了剪复杂度没变化,所以没啥区别~
下面分析大佬的代码~
大佬发现快乐数其实是固定的那几个数,于是大佬选择hard code 100以内的快乐数:
const list = new Set([1, 7, 10, 13, 19, 23, 28, 31, 32, 44, 49, 68, 70, 79, 82, 86, 91, 94, 97, 100]);
// 把大于100的转换回100
while(n>100){
n=...
}
return list.has(n);
执行用时 :64 ms, 在所有 JavaScript 提交中击败了96.53%的用户
内存消耗 :35.1 MB, 在所有 JavaScript 提交中击败了80.00%的用户
快慢指针!因为一定会重复,分两个指针,慢的一次走一步,快的走两步,要不最后快的是1,要不最后快的等于慢的。
看代码吧我说的不清楚!!
var isHappy = function (n) {
// slow 在第一步
let slow = sum(n);
// fast 在第二步
let fast = sum(slow);
while(slow != fast && fast != 1){
// slow往前走一步
slow = sum(slow)
// fast往前走两步
fast = sum(sum(fast))
}
return fast === 1
// 求每位平方的和
function sum(n){
let sum=0;
for(let i of n.toString()){
sum += i*i;
}
return sum;
}
};
执行用时 :84 ms, 在所有 JavaScript 提交中击败了34.62%的用户
内存消耗 :36.4 MB, 在所有 JavaScript 提交中击败了20.00%的用户
帅是帅,慢也是慢。还是方法1牛逼。