[ 力扣66 ] 我终于找到了js中BigInt的用武之地——大数运算 | 刷题打卡

1,970 阅读4分钟

题目名称:加一

题目地址:leetcode-cn.com/problems/pl…

给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 你可以假设除了整数 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)
};

但是:

image.png

image.png

由于大数精度问题,这种直接转化的方式是大错特错的,虽然这样不行,但能想到这种解法也值得鼓励啦~

那么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进行计算

说明

  1. 本题解已同步leetcode-js-simple/09.[ 66 ] 加一,可以复制代码进行调试。
  2. 总结出了一套亲测有效的前端无痛刷题项目,有助于算法小白平稳入门,详见leetcode-js-roadmap,希望对从零开始刷题的前端小伙伴们带来帮助~

本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情