LeetCode刷题挑战-javascript:67.二进制求和

530 阅读1分钟

background.webp

「这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战

题目

给你两个二进制字符串,返回它们的和(用二进制表示)。

输入为 非空 字符串且只包含数字 1 和 0。

 

示例 1:

输入: a = "11", b = "1"

输出: "100"

示例 2:

输入: a = "1010", b = "1011"

输出: "10101"  

提示:

  • 每个字符串仅由字符 '0' 或 '1' 组成。
  • 1 <= a.length, b.length <= 10^4
  • 字符串如果不是 "0" ,就都不含前导零。

解题思路

方法一:不用加法的二进制求和

  • a & b 的结果,左移一位(<< 1)就得到进位数
  • a ^ b ,异或,其实就是不带进位的加法,结果更新给 a
  • 求出得到进位数,更新给 b
/**
 * @param {string} a
 * @param {string} b
 * @return {string}
 */
const addBinary = (a, b) => {
  a = parseInt(a, 2);
  b = parseInt(b, 2);
  while (b != 0) {
    let carry = a & b;
    a = a ^ b;
    b = carry << 1;
  }
  return a.toString(2);
};

但是很可惜,我们提交代码之后会发现并不可行。原因是JavaScript中的 parseInt 在将很大的二进制转十进制时会溢出。如下👇:

111.png

方法二:逐位相加

  • 先让 a 和 b 对齐,补齐前面的0
  • 从右往左,逐位相加,用 carry 变量记录是否 进1
  • 每一位的计算结果放到 res 数组里,最后转成字符串
/**
 * @param {string} a
 * @param {string} b
 * @return {string}
 */
const addBinary = (a, b) => {
  while (a.length > b.length) b = '0' + b;
  // 先对齐
  while (a.length < b.length) a = '0' + a;
  let res = new Array(a.length);
  let sum = 0;
  // 进位
  let carry = 0; 
  for (let i = a.length - 1; i >= 0; i--) {
    sum = Number(a[i]) + Number(b[i]) + carry;
    if (sum >= 2) {
      res[i] = sum - 2;
      carry = 1;
    } else {
      res[i] = sum;
      carry = 0;
    }
  }
  if (carry) res.unshift(1); // 循环结束还要进1,则在res数组前端加一个1
  return res.join('');
};

方法三:将上面方法根据位运算改进一下

  • 当前位不带进位相加的结果是异或求出的
  • 当前位AND得出当前位的进位,考虑上之前的进位,算出给下一轮迭代的进位
/**
 * @param {string} a
 * @param {string} b
 * @return {string}
 */
const addBinary = (a, b) => {
  while (a.length > b.length) b = '0' + b;
  while (a.length < b.length) a = '0' + a; 
  let res = new Array(a.length);
  let val;              // 当前位不进位的相加结果
  let carry;            // 当前位的进位
  let carryFromBefore = 0;  // 当前相加是否有来自上一位的进1
  for (let i = a.length - 1; i >= 0; i--) {
    val = Number(a[i]) ^ Number(b[i]);   // 异或是不带进位的相加
    carry = Number(a[i]) & Number(b[i]); // 求出当前位的进位
    if (carryFromBefore) { // 有来自上一位的进位
      if (val == 0) {
        val = 1;        // 加上进位 变为1
      } else {         // 当前位1 + 进位1 = 2
        carry = 1;      // 往前进1
        val = 0;        // 当前位为0
      }
    }
    carryFromBefore = carry; // 给下一轮迭代使用的进位
    res.unshift(val);        // 从res数组的前头推入
  }
  if (carry) res.unshift(1); // 循环结束,还有进位,就要多加1
  return res.join('');
};

结束语

这里是小葵🌻,只要把心朝着太阳的地方,就会有温暖~

让我们一起来攻克算法难关吧!!