算法题-大数乘法

281 阅读2分钟

要求

  • 输入两个string类型的值,均由0-9组成,最大长度为10000
  • 求两个数之积

思路

  • 按照乘法的步骤一步步来计算
  • 即:个十百千...依次计算,最后给每组结果添加相应个数的0,然后把全部加起来

细节

  • 竖式乘法计算步骤与两个数的长度有关,按照自己熟悉的顺序摆放位置
  • 进位使用后要清零
  • 内圈每一轮最后一次的进位不再是进位,直接保留在原数字上
  • 外圈每轮开始时要清零进位

代码

function bigFlex(a, b) {
  // 变成数组,然后翻转数组,方便从个位开始计算
  a = a.split("").reverse();
  b = b.split("").reverse();
  let more = 0;
  let result = [];
  // 要注意,竖式乘法一般的计算步骤与两个数的长度有关,需要把长的放上面,短的放下面
  let numa,
    numb,
    isLonger = false;
  a.length > b.length ? (isLonger = false) : (isLonger = true);
  if (isLonger) {
    numa = a;
    numb = b;
  } else {
    numa = b;
    numb = a;
  }
  // 开始计算,外圈为较短的数,内圈为较长的数
  numa.forEach((item, index) => {
    more = 0; //每轮开始时进位要清零
    result[index] = [];
    numb.forEach((x, idx) => {
      let r = "" + (x * item + more);
      more = 0; //注意每次用完进位要清零
      result[index].push(r[r.length - 1]);
      if (r.length > 1) {
        more = r[0] - 0;
      }
      if (idx + 1 == numb.length && more != 0) { //每轮最后一次的进位直接保留在开头,不再是进位
        result[index].push("" + more);
      }
    });
  });
  let ret = 0;
  result.forEach((item, index) => { //二维数组result每一项就是一轮计算的结果,依次添加相应数量的0
    let num = item.reverse();
    for (let i = 1; i <= index; i++) {
      num.push("0");
    }
    ret += Number(num.join("")); //相加
  });

  return ret;
}

方法比较简单粗暴,循环比较多,但逻辑上比较简单

补充

  • 上面方法有一个致命问题:使用竖式乘法最后会涉及每一轮相乘结果的相加,而相乘结果本身也非常大,可能超出正常加法计算的范围。

  • 解决:新增大数加法

function bigAdd(a, b) {
  a = a.split("").reverse();
  b = b.split("").reverse();
  // console.log(a, b); //***************************************************************** */
  let result = [],
    ret = [];
  let more = 0;
  let len = 0,
    flag = "a";
  if (a.length > b.length) {
    len = b.length;
    flag = "b";
  } else {
    len = a.length;
    flag = "a";
  }
  // console.log(flag); //*************************************************************** */
  // 循环,取较短的长度为循环次数
  for (let i = 0; i < len; i++) {
    let r = a[i] - 0 + (b[i] - 0) + more;
    // console.log(r, "1r"); //********************************************* */
    more = 0;
    r = "" + r;
    result.push(r[r.length - 1]);
    if (r.length > 1) {
      more = r[0] - 0;
    }
  }
  // if (more != 0) {
  if (flag == "a") {
    for (let i = len; i < b.length; i++) {
      // console.log(flag, more, b[i]);
      if (more == 0) break;
      let r = b[i] - 0 + more;
      // console.log(r, "2r");
      more = 0;
      r = "" + r;
      b[i] = r[r.length - 1];
      if (r.length > 1) {
        more = r[0] - 0;
      }
    }
    ret = b.splice(len);
    // b[len] = b[len] - 0 + more;
  } else if (flag == "b") {
    // a[len] = a[len] - 0 + more;
    for (let i = len; i < a.length; i++) {
      // console.log(flag, more, a[i], a.length);
      if (more == 0) break;
      let r = a[i] - 0 + more;
      // console.log(r);
      more = 0;
      r = "" + r;
      a[i] = r[r.length - 1];
      if (r.length > 1) {
        more = r[0] - 0;
      }
    }
    ret = a.splice(len);
  }
  // }
  // console.log(ret, 1);
  if (more != 0) {
    ret.push(more);
  }
  ret = result.concat(ret);
  // console.log("return,,", ret);
  return ret.reverse().join("");
}
  • 修改乘法代码,将最后的相加改为使用大数加法解决
function bigFlex(a, b) {
  // 变成数组,然后翻转数组,方便从个位开始计算
  a = a.split("").reverse();
  b = b.split("").reverse();
  let more = 0;
  let result = [];
  // 要注意,竖式乘法一般的计算步骤与两个数的长度有关,需要把长的放上面,短的放下面
  let numa,
    numb,
    isLonger = false;
  a.length > b.length ? (isLonger = false) : (isLonger = true);
  if (isLonger) {
    numa = a;
    numb = b;
  } else {
    numa = b;
    numb = a;
  }
  // 开始计算,外圈为较短的数,内圈为较长的数
  numa.forEach((item, index) => {
    more = 0; //每轮开始时进位要清零
    result[index] = [];
    numb.forEach((x, idx) => {
      let r = "" + (x * item + more);

      more = 0; //注意每次用完进位要清零
      result[index].push(r[r.length - 1]);
      // console.log(r, more, result[index]);
      if (r.length > 1) {
        more = r[0] - 0;
      }
      if (idx + 1 == numb.length && more != 0) {
        //每轮最后一次的进位直接保留在开头,不再是进位
        result[index].push("" + more);
      }
    });
  });
  let ret = 0;
  result.forEach((item, index) => {
    //二维数组result每一项就是一轮计算的结果,依次添加相应数量的0
    let num = item.reverse();
    for (let i = 1; i <= index; i++) {
      num.push("0");
    }
    // console.log(num.join(""));
    // ret += Number(num.join("")); //相加
    // console.log("add", ret, num.join(""));
    ret = bigAdd("" + ret, num.join(""));
    // console.log("ret", ret);
  });

  return ret;
}