面试官:写一个函数,这个函数接收两个超长字符串,字符串都是有数字组成的,函数返回这两个字符串相加后的结果。
我: 这个很简单啊,只需要将两个字符串转换成数字类型,返回他们相加的结果就好了。于是我写下了以下的程序。
function sumup(s1, s2) {
return Number(s1) + Number(s2)
}
面试官:不不不,这个程序不对,我说的是超长字符串,无法转换为数字类型进行存储的,比如几百位的那种。
现在我明白了面试官想要问的问题,于是我陷入了思考。
整理思路,写出代码
这个问题其实并不算很难,所以我很快就想出了一个思路:既然这个字符串无法转换为数字类型进行运算,那我们可以像手动算加法的时候,从最后一位开始,再解决进位的问题,问题就解决了。
第一步:因为是从最后一位开始进行运算的,所以我首先想到的就是一个for的倒叙循环,这个循环的开始项,是从比较长的那个字符串的最后一位的下标开始的。
function sumup(s1, s2) {
let len = s1.length;
if(len < s2.length) len = s2.length
for(let i = len; i >= 0; i--) {
// 后续逻辑
}
}
第二步:接下来我们就要每一位的运算了,之前提到了进位的问题,那么顺便就把这个也解决了吧。首先根据下标取出字符串的最后一位,因为字符串有一个短的,所以在根据取值的时候也可能取不到值(undefined),所以在取值的时候做一个非真值判断就可以了,如果值为假的,则返回0。
进位的实现:可以事先准备一个变量,默认值为0,在我们每次进行每位的运算时,将相加结果大于10的部分,存到这个变量中,在下一位运算的时候加上这个值就可以了,思路可以,接下来上代码。
function sumup(s1, s2) {
let len = s1.length;
if(len < s2.length) len = s2.length;
let res = "";
let ten = 0;
for(let i = len; i >= 0; i--) {
// 后续逻辑
const e1 = s1[i] || 0
const e2 = s2[i] || 0
// 这里因为 ten 的默认值是0,所以第一次循环就可以加上这个变量,0嘛,加不加不影响结果的
const result = e1 + e2 + ten;
// 这里res为啥不用+=呢?
// 因为我们是从最后一位开始运算的,所以新运算出来的值应当拼接在前面
res = result % 10 + res;
ten = Math.floor(result / 10)
}
return res;
}
第三步:检查自己的代码。这一步也是很重要,写完代码之后需要回想自己的代码逻辑,有没有遗漏的地方。上面的这段代码就有一个逻辑问题,最后一次循环算出来的进位,并没有拼接到结果前面,所以还需要一些改动
function sumup(s1, s2) {
let len = s1.length;
if(len < s2.length) len = s2.length;
let res = "";
let ten = 0;
for(let i = len; i >= 0; i--) {
// 后续逻辑
const e1 = s1[i] || 0
const e2 = s2[i] || 0
// 这里因为 ten 的默认值是0,所以第一次循环就可以加上这个变量,0嘛,加不加不影响结果的
const result = Number(e1) + Number(e2) + ten;
// 这里res为啥不用+=呢?
// 因为我们是从最后一位开始运算的,所以新运算出来的值应当拼接在前面
res = result % 10 + res;
ten = Math.floor(result / 10)
}
// 补充的部分
if(ten != 0) res = ten + res;
return res;
}
到了这里,我面试时写的代码就已经写好了,于是我就提交了。function("111111", "222") 输出: 333111; 。。。 是的,输出的不是 111333,程序的运行出错了,但是我却不知道错在哪了。面试官说已经理解我的思路,程序的bug私下去调。
解决问题
本着对技术钻研的态度,我也不可能放弃这道题目,所以在面试结束后,我就去研究代码的bug了。
终于最终是被我找到了问题,程序中在进行for循环的时候,下标是较长字符串最后一位的下标,但是这个下标却不是较短字符串最后一位的下标,所以在取值的时候,取到的较短字符串的值就不是它的最后一位了。
问题的关键已经找到了,接下来就是解决了,也就是需要保证在循环的时候,取到的位数,都是按照最后一位往前推移的。所以采用从0开始正循环,在取最后一位的时候,下标通过字符串的总长度减去循环的(i+1)来获得。
// 最终代码
function sumUp(s1, s2) {
const lenS1 = s1.length
const lenS2 = s2.length
let len = lenS1;
if (len < lenS2) len = lenS2
let res = ''
let ten = 0
for (let i = 0; i < len; i++) {
const e1 = s1[lenS1 - i - 1] || '0'
const e2 = s2[lenS2 - i - 1] || '0'
const result = Number(e1) + Number(e2) + ten
ten = Math.floor(result / 10)
res = result % 10 + res
}
if (ten != 0) res = ten + res;
return res
}
问题思考
上面的代码已经解决了面试官的问题,但是我在想,如果传入的字符串是小数形式呢,各位看官有没有思路,欢迎留言。