需求:在 javascript 中不借助任何 BigInteger 库对两个字符串形式的非负整数 num1 和 num2 求和。
示例: “9007199254740992” + “9” = “9007199254741001”
虽然开头的需求已经明确了解题规则:不借助任何 BigInteger 库来实现它。但是此处我还是想把 BigInt 放出来做下对照,以免日后忘记它的存在。
ES2020 引入了一种新的数据类型 BigInt(大整数)来解决这个问题。BigInt 只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。 例如:9007199254740992n + 9n = 9007199254741001n
解题思路
实际上这道题求的是两个字符串相加,我们就用字符串"11"+"90"来回忆下小时候老师教我们简单的加法是如何算的:
看到上图的加法运算它相当于将两个字符串从最右边开始相加,可用如下代码表示:
let indexA = num1.length - 1
let indexB = num2.length - 1
let x = num1.charAt(indexA);
let y = num2.charAt(indexB);
let sum = Number(x) + Number(y)
我们把计算的结果存放到一个新的字符串中,字符串每次只能存放一位数字(例如:个位、十位、百位...等等)。但是我们相加的结果 sum 可能是两位数,所以我们只取他的个位数,十位数要往前进一位。比如我们计算 num1 和 num2 的倒数第二位的和为 “10” ,因此我们的进位值 “1” 用 carry 来表示。
let indexA = num1.length - 2
let indexB = num2.length - 2
let x = num1.charAt(indexA);
let y = num2.charAt(indexB);
let sum = Number(x) + Number(y) + carry
这个 carry 就是上一步相加结果的进位,上一步如果进位了就是 “1”,如果没进位就是 “0”。理清了上面的相加过程,剩下的就是一些边界条件的判断。最后不要忘了对字符串进行反转,因为我们相加的时候是从 num1和num2 的尾部开始加的,以下是实现的完整码:
function addStrings(num1, num2) {
let indexA = num1.length - 1;
let indexB = num2.length - 1;
let carry = 0; //存进位值
let result = ""; //存字符串结果
while (indexA >= 0 || indexB >= 0 || carry != 0) {
let x = indexA < 0 ? 0 : num1.charAt(indexA--);
let y = indexB < 0 ? 0 : num2.charAt(indexB--);
let sum = Number(x) + Number(y) + carry;
result += sum % 10; //只取他的个位数
carry = Math.floor(sum / 10); //取进位值
}
return result.split("").reverse().join(""); //对字符串反转得到结果
}
addStrings("9007199254740992", "9"); // 9007199254741001
总结
这道题其实非常简单,解题思路就是先从两个字符串的最后一位开始相加(“逢十”进位),最后将得到的字符串反转就是我们的结果值。