zoukankan      html  css  js  c++  java
  • [LeetCode] Multiply Strings | 大整数字符串乘法

    https://leetcode.com/problems/multiply-strings/?tab=Description

    模拟我们平时做多位乘法的操作,依次把一个乘数与另一个乘数的每一位分别相乘,最后加和。

    class Solution {
    public:
        string multiply(string num1, string num2) {
            if (num1 == "0" || num2 == "0") return "0";
            
            int n1 = num1.size(), n2 = num2.size();
            string ret = "0", zeros = "";
            for (int i = n2 - 1; i >= 0; --i) {
                // compute num1 * nums2[i]
                string numi = "";
                int fac = num2[i] - '0', carry = 0;
                for (int j = n1 - 1; j >= 0; --j) {
                    carry += (num1[j] - '0') * fac;
                    numi = to_string(carry % 10) + numi;
                    carry /= 10;
                }
                if (carry != 0) numi = to_string(carry) + numi;
                numi += zeros; zeros += "0";
                // add the result
                ret = addBinary(ret, numi);
            }
            
            return ret;
        }
        
        string addBinary(string a, string b) {
            int p1 = a.size() - 1, p2 = b.size() - 1, carry = 0;
            
            string ret = "";
            while (true) {
                if (p1 >= 0) carry += (a[p1--] - '0');
                if (p2 >= 0) carry += (b[p2--] - '0');
                string next_digit = to_string(carry % 10);
                carry /= 10;
                if (p1 >= 0 || p2 >= 0 || carry != 0 || next_digit != "0") {
                    ret = next_digit + ret;
                } else break;
            }
            // remove the prefix '0'
            int i = 0;
            while (i < ret.size()) {
                if (ret[i] != '0') break;
                i++;
            }
            if (ret.empty()) ret = "0";
            
            return ret.substr(i, ret.size() - i);
        }
    };
    

    其中addBinary函数就是大整数加法(leetcode 67: https://leetcode.com/problems/add-binary/
    )。

    上面这份代码可以AC。不过,虽然时间复杂度是O(n^2),但是性能不高(C++ 190ms左右)。

    -----懒惰与勤劳的分界线-----

    举个例子,看能不能将代码写得更简单些,以乘法324 * 78为例,我们做乘法的方式是:

    ---------
        3 2 4
    x     7 8
    ---------
      2 5 9 2
    2 2 6 8
    ---------
    2 5 2 7 2
    

    我们将位数按从右往左的顺序编号为0,1,2... 观察结果:

    • 第0位 = 4 * 8(除去进位),在两个乘数的位置是(0, 0)
    • 第1位 = 2 * 8 + 4 * 7 + 结果第0位的进位(后除去进位),分别在两个乘数的位置是(1, 0), (0, 1)
    • 第2位 = 3 * 8 + 2 * 7 + 结果第1位的进位(后除去进位),分别在两个乘数的位置是(2, 0), (1, 1)
    • 第3位 = 3 * 7 + 结果第2位的进位(后除去进位),在两个乘数的位置是(2, 1)
    • 第4位 = 第3位的进位

    规律:结果的第i位 = 两个乘数位置相加恰好为i的数位乘积的加和,再加上结果第i-1位的进位

    实现上,可以用一个int数组mul(大小为两个乘数数位长度之和)存放数位乘积,按mul[i+j] += (num1[i] * num2[j]),然后再把进位算进去,构造出最后的结果。

    class Solution {
    public:
        string multiply(string num1, string num2) {
            if (num1 == "0" || num2 == "0") return "0";
            
            reverse(num1.begin(), num1.end());
            reverse(num2.begin(), num2.end());
            
            int n1 = num1.size(), n2 = num2.size();
            vector<int> mul(n1 + n2, 0);
            for (int i = 0; i < n1; ++i) {
                int mul1 = num1[i] - '0';
                for (int j = 0; j < n2; ++j) {
                    mul[i+j] += mul1 * (num2[j] - '0');
                }
            }
            
            string ret = "";
            int carry = 0;
            for (int i = 0; i < mul.size(); ++i) {
                carry += mul[i];
                ret = to_string(carry % 10) + ret;
                carry /= 10;
            }
            if (carry != 0) ret = to_string(carry) + ret;
            // remove the prefix '0'
            int i = 0;
            while (i < ret.size() && ret[i] == '0') i++;
            
            return ret.substr(i, ret.size() - i);
        }
    };
    

    上面这份代码的时间复杂度依然是$O(n^2)$,但是跑leetcode的所有数据降到了10ms左右,性能明显提升。

    另外值得一提的是,大数乘法可以通过Fast Fourier Transform(FFT)算法计算多项式乘积将复杂度降到O(n logn),而FFT则是基于分治的思想,这里就不深入下去了。

  • 相关阅读:
    java抽象类和接口
    java的三大特征:封装,继承和多态
    java的数组
    django 4.get接口开发
    django 3.post接口开发
    C# 程序启动最小化至任务栏及闪烁
    续Html5
    使用intellij idea搭建MAVEN+SSM(Spring+SpringMVC+MyBatis)框架
    Spring MVC拦截器
    Html5高级
  • 原文地址:https://www.cnblogs.com/ilovezyg/p/6421887.html
Copyright © 2011-2022 走看看