如何高效终止判断快乐数的递归函数,避免出现无限循环问题?
问题根源
你实现的是快乐数判断逻辑,非快乐数的各位平方和计算最终会进入固定循环(4→16→37→58→89→145→42→20→4),不会走到1的终止条件,因此会无限递归。另外你当前代码存在拼写bug:求和函数定义为sqaureSum,但递归函数中调用的是squareSum,需要先修正拼写。
优化方案
方案1:基于数学规律的极简终止条件(效率最高,无额外开销)
数学上已证明所有非快乐数的平方和运算最终都会落到4,你之前加的x === 4终止条件实际效率并不低——任意大的整数最多经过十几次平方和运算就会落到个位数,不存在效率问题。可以直接基于这个规则调整递归函数,自定义返回值适配后续计算:
function recursion(x) { // 自定义返回规则:是快乐数返回1,非快乐数返回0,可按需调整 if (x === 1) return 1; if (x === 4) return 0; x = squareSum(x); return recursion(x); }
方案2:递归加访问标记(通用循环检测方案,适配自定义规则)
如果后续需要调整逻辑,不想依赖固定终止值,可以给递归函数增加访问集合参数,检测到重复值就说明进入循环,直接返回结果:
function recursion(x, visited = new Set()) { if (x === 1) return 1; // 出现重复值说明进入循环,不是快乐数 if (visited.has(x)) return 0; visited.add(x); x = squareSum(x); return recursion(x, visited); }
方案3:快慢指针迭代实现(无递归栈溢出风险,空间复杂度O(1))
如果输入数值很大,递归可能触发调用栈溢出,推荐用Floyd快慢指针法迭代实现,不需要额外存储访问集合,也不会有栈溢出问题:
function isHappy(n) { function squareSum(num) { let sum = 0; while (num > 0) { const digit = num % 10; sum += digit * digit; num = Math.floor(num / 10); } return sum; } let slow = n; let fast = squareSum(n); while (fast !== 1 && slow !== fast) { slow = squareSum(slow); fast = squareSum(squareSum(fast)); } return fast === 1 ? 1 : 0; }
附属优化:平方和函数改迭代
你当前的squareSum本身也是递归实现,嵌套在快乐数递归逻辑中会增加栈溢出风险,改成迭代版本更稳定:
function squareSum(n){ let sumTotal = 0; while(n > 0){ sumTotal += Math.pow(n % 10, 2); n = Math.floor(n / 10); } return sumTotal; }
内容的提问来源于stack exchange,提问作者dani
相关产品推荐
相关产品推荐

