我正在实施 HAPPY NUMBER,但无法弄清楚为什么我的 WHILE 循环永远不想停止执行?我知道这对于像 2 这样的少数输入情况会失败,这就是为什么我计划将所有总和存储在一个数组中,然后检查是否有任何数字正在执行只会导致无限循环。
var storeNum = [];
var isHappy = function(n) {
while(n > 1){
n = findSum(n);
storeNum.push(n);
}
if(n == 1){
console.log("HAPPY NUMBER");
return true;
}
return false;
};
function findSum(n) {
let sum = 0;
while(n != 0){
let rem = Math.floor(n % 10);
sum = sum + rem * rem;
n = n/10;
}
return sum;
}
不明白为什么我的 WHILE 循环永远不想停止执行?
嗯,这是预料之中的。代码挑战说:
重复这个过程,直到数字等于 1(它将停留的位置),或者它循环无限循环不包括 1.
这就是你的代码中发生的事情:它在一个循环中无限循环。您的代码需要检测存在cycle。
我计划将所有总和存储在一个数组中,然后检查是否有任何数字正在执行只会导致无限循环。
你不应该这样做later,因为当你陷入无限循环时就没有了。当检测到循环时,您应该中断循环。
所以循环条件应该有一个额外的检查。为了使其正常工作,循环体应首先将数字添加到集合中,然后才计算下一个值:
while(n > 1 && !storeNum.includes(n)){
storeNum.push(n);
n = findSum(n);
}
另一个问题是你的数组是一个全局变量,这意味着在你的函数的第二次调用中,第一次调用的值仍然在那个数组中。这不是你想要的。而是将该数组定义为局部变量:
const storeNum = [];
while(n > 1 && !storeNum.includes(n)){
storeNum.push(n);
n = findSum(n);
}
现在可以用了。
您仍然可以通过以下方式提高此解决方案的效率:
避免
findSum
中的浮点计算,因为目前除以10在大多数情况下不是整数。也受益于 +=
运营商:
const rem = n % 10; // No more need of floor()
sum += rem * rem; // Can use += operator
n = (n - rem) / 10; // Make sure the result is integer
使数组成为一个集合。这样查找速度更快:
const storeNum = new Set;
while(n > 1 && !storeNum.has(n)){
storeNum.add(n);
n = findSum(n);
}
保留以前调用的结果。
为此,全局变量 很有用。它可以是具有布尔值的地图。我们已经可以用一个条目初始化这张地图:1 是一个快乐的数字。
这导致这段代码:
const memo = new Map;
memo.set(1, true);
var isHappy = function(n) {
const storeNum = new Set;
while(!storeNum.has(n) && !memo.has(n)) {
storeNum.add(n);
n = findSum(n);
}
const result = !!memo.get(n); // This will be false when not in memo
// All numbers in the traversed path have same outcome
for (const m of storeNum) memo.set(m, result);
return result;
};
function findSum(n) {
let sum = 0, rem;
while (n != 0) {
rem = n % 10;
sum += rem * rem;
n = (n - rem) / 10;
}
return sum;
}