题目名称:加一
给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 你可以假设除了整数 0 之外,这个整数不会以零开头。
示例 1:
输入:digits = [1,2,3]
输出:[1,2,4]
解释:输入数组表示数字 123。
示例 2:
输入:digits = [4,3,2,1]
输出:[4,3,2,2]
解释:输入数组表示数字 4321。
示例 3:
输入:digits = [0]
输出:[1]
解法
- 经过若干次提交后发现,这其实是十进制加法;示例中没有给出包含9的数字数组测试真的很坑~
一、BigInt解决大数+1
机智如你很快发现这不就是十进制+1而已吗,那么转化为数字之后+1再转回来不就完事了? 比如这样:
/**
* @param {number[]} digits
* @return {number[]}
*/
var plusOne = function (digits) {
// * 先转化为数字
let numStr = digits.join('')
const num = Number(numStr)
if(isNaN(num)) throw new Error('Input number list can not be transformed to Integer.')
return (num+1).toString().split('').map(Number)
};
但是:
由于大数精度问题,这种直接转化的方式是大错特错的,虽然这样不行,但能想到这种解法也值得鼓励啦~
那么js中有没有一种数据结构可以用来处理大数运算呢?还真有!
- BigInt
BigInt 是一种内置对象,它提供了一种方法来表示大于 253 - 1 的整数。这原本是 Javascript中可以用 Number 表示的最大数字。BigInt 可以表示任意大的整数。
- 几种创建BigInt类型数据的方式
const theBiggestInt = 9007199254740991n;
const alsoHuge = BigInt(9007199254740991);
// ↪ 9007199254740991n
const hugeString = BigInt("9007199254740991");
// ↪ 9007199254740991n
const hugeHex = BigInt("0x1fffffffffffff");
// ↪ 9007199254740991n
const hugeBin = BigInt("0b11111111111111111111111111111111111111111111111111111");
// ↪ 9007199254740991n
注意:不能和任何 Number 实例混合运算,两者必须转换成同一种类型。在两种类型来回转换时要小心,因为 BigInt 变量在转换成 Number 变量时可能会丢失精度。
toString属性
BigInt.prototype.toString() 返回以指定基数(base)表示指定数字的字符串。覆盖 Object.prototype.toString() 方法。
那么这道题很容易就想到了这样的解法:
var plusOne = function (digits) {
const numStr = digits.join('')
const numBig = BigInt(numStr)
const resBig = numBig + BigInt(1) // 或者 + 1n 也行
return resBig.toString().split('').map(Number)
};
🤹♀️完美~
二、递归解法逢九判断
- 从后向前遍历,如果当前数为9,就置为0,否则就+1返回
/**
* @param {number[]} digits
* @return {number[]}
*/
var plusOne1 = function (digits) {
for (let i = digits.length - 1; i >= 0; i--) {
if (digits[i] !== 9) {
digits[i]++
return digits
} else {
digits[i] = 0
}
}
// * 如果走到这里,说明第一项也是9,那么前面补个1
digits = [1, ...digits]
return digits
};
三、递归的另一种解法
- 先加1再判断也是可以哒
/**
* @param {number[]} digits
* @return {number[]}
*/
var plusOne2 = function (digits) {
for (let i = digits.length - 1; i >= 0; i--) {
digits[i]++
digits[i] %= 10
if (digits[i] !== 0) {
return digits
}
}
// * 如果走到这里,说明第一项也是9,那么前面补个1
digits = [1, ...digits]
return digits
};
测试用例
// 测试用例
let test = [1, 2, 3]
let test1 = [9]
let test2 = [9, 9]
let test3 = [6,1,4,5,3,9,0,1,9,5,1,8,6,7,0,5,5,4,3]
console.time('执行用时');
console.log(plusOne(test));
console.log(plusOne1(test1));
console.log(plusOne2(test2));
console.log(plusOne(test3))
console.timeEnd('执行用时');
总结
- 大数相加会有精度问题,可以借助
BigInt进行计算
说明
- 本题解已同步leetcode-js-simple/09.[ 66 ] 加一,可以复制代码进行调试。
- 总结出了一套亲测有效的前端无痛刷题项目,有助于算法小白平稳入门,详见leetcode-js-roadmap,希望对从零开始刷题的前端小伙伴们带来帮助~
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情