JavaScript实现LeetCode Excel列名转换递归出现无限循环问题
问题背景
- 正在学习JavaScript数据结构与算法,练习递归逻辑实现
- 已知递归需要规避无限循环问题,但尚未掌握正确的递归实现方法,递归触发的无限循环是当前的核心学习难点
- 本次调试的问题为LeetCode算法题《Excel表列名称》,题目地址:Excel表列名称
- 自行编写的递归实现运行时触发无限循环,需要排查问题根因,问题代码如下:
/** * @param {number} columnNumber * @return {string} */ var convertToTitle = function(columnNumber, lis=[]) { const chars = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"] let digit = 0; console.log("===== start") if (columnNumber === 0) return; if (columnNumber <= chars.length) { console.log("columnNumber",columnNumber, "<= chars.length", chars.length) lis.push(chars[columnNumber-1]) console.log("lis.join('')", lis.join("")) return; } else { while (true) { if (columnNumber > chars.length ^ digit) { console.log("should bne passed if") digit+=1; continue; } else { console.log("should bne passed else") digit-=1; let num = 1; while (true) { console.log(columnNumber, (chars.length ^ digit) * num, num, "2 while") if (columnNumber > (chars.length ^ digit) * num) { num+=1; continue } else { console.log("2 else") num-=1; lis.push(chars[num-1]); console.log("function while end".toUpperCase() , "lis:", lis, "passed num", columnNumber - (chars.length ^ digit) * num) convertToTitle(columnNumber - (chars.length ^ digit) * num, lis) } } } } } }
无限循环根因
代码存在4个核心问题,共同导致无限循环:
- 运算符优先级错误:JS中
>比较运算符的优先级高于位异或运算符^,代码中columnNumber > chars.length ^ digit的实际执行逻辑是(columnNumber > chars.length) ^ digit,和预期的「比较columnNumber与26的digit次方大小」逻辑完全不符,判断条件从根源失效。 - 运算符使用错误:错把位异或运算符
^当成数学幂运算使用。JS里^是按位异或操作,比如26 ^ 1结果为27、26 ^ 2结果为24,和预期要计算的261=26、262=676完全无关,所有基于这个计算的数值判断全部错误。 - 循环无终止出口:代码中嵌套的两层
while(true)循环没有设置任何break或return终止逻辑,即便执行了递归调用,当前函数栈内的循环也不会停止,递归返回后会继续在循环内执行,必然触发无限循环。 - 递归逻辑设计混乱:递归本身就是用来处理多层级重复计算的,代码在递归内部又嵌套两层循环手动计算位数,把迭代和递归逻辑混写,完全违背递归的设计思路,逻辑复杂度陡增,很容易出现死循环问题。
除此之外,代码的递归终止逻辑也有缺陷:columnNumber===0时直接return没有返回拼接好的结果,递归调用时也没有接收返回值,就算修复死循环问题也无法返回正确的列名字符串。
正确递归实现参考
Excel表列名称本质是1起始的26进制转换,递归逻辑不需要嵌套循环,只需要每次处理最低位、递归处理高位即可,参考实现:
/** * @param {number} columnNumber * @return {string} */ var convertToTitle = function(columnNumber) { // 递归终止条件:数值归0返回空串 if (columnNumber === 0) return ''; // 把1起始的数值转成0起始,适配26个字母的下标 columnNumber--; // 拼接高位递归结果 + 当前位字符 return convertToTitle(Math.floor(columnNumber / 26)) + String.fromCharCode(65 + columnNumber % 26); };
内容的提问来源于stack exchange,提问作者Sana
相关产品推荐
相关产品推荐

