每日leetcode

43. 字符串相乘 - 力扣(LeetCode)

题目

给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。

注意:不能使用任何内置的 BigInteger 库或直接将输入转换为整数。

示例 1:

输入: num1 = "2", num2 = "3"
输出: "6"

示例 2:

输入: num1 = "123", num2 = "456"
输出: "56088"

提示:

  • 1 <= num1.length, num2.length <= 200
  • num1 和 num2 只能由数字组成。
  • num1 和 num2 都不包含任何前导零,除了数字0本身。

思路

  1. 一个比较直观的思路是将他们分别转换成数字再逐位做乘法,但是会出现溢出问题,这可能也是为什么要设计成字符串乘法的原因吧。
  2. 那么没有别的选择了,我们只能在字符串上按位进行逐位乘法了。
  3. 思路还是比较简单的,但是实现起来比较麻烦,跟竖式一样,我们每次根据num2未计算的最小位的数字去和num1的每个数字相乘,得出结果的最小位即为该位的最终结果,然后剩下的部分参与到下一位的运算中去。
  4. 不断地重复步骤3的步骤知道所有num2的所有位都完成计算。

代码实现

class Solution {
public:
    string multiply(string num1, string num2) {
        if(num1=="0" || num2=="0") return "0";
        int n1 = num1.size(), n2 = num2.size(), a, tmp = 0, addNum = 0;
        string ans = "";
        reverse(num1.begin(), num1.end());
        reverse(num2.begin(), num2.end());
        // 当num2只有一位时
        for(int i = 0; i < n2; ++i) {
            a = num2[i] - '0'; // 每次取未计算的最低位去乘
            int length = ans.size();
            for(int j = 0; j < n1; ++j) {
                if(i+j < length) addNum += ans[i+j] - '0'; // 如果结果的最低位在ans的范围内,还要补上ans在对应位置上的值。
                tmp = ((num1[j]-'0') * a) + addNum; // 计算对应位的结果
                if(i+j < length) ans[i+j] = (tmp%10)+'0'; // 如果该位已经有数字,直接修改结果
                else ans += (tmp%10)+'0'; // 如果该位没有数字,则加上
                addNum = tmp / 10;
            }
            if(addNum > 0) ans += addNum+'0';// 如果最后还有进位,要补上进位
            addNum = 0; // 计算完最低位要归零
        }
        reverse(ans.begin(), ans.end());
        return ans;
    }
};

复杂度分析

  • 时间复杂度:reverse()操作的时间复杂度为O(max(n1, n2));计算的乘积的时间复杂度为O(n1*n2),添加字符和修改字符都是在同一时间发生的一次操作,所以总的时间复杂度为O(n1*n2)。
  • 空间复杂度:因为reverse所需的空间复杂度为O(1),若需要考虑输出字符串的话,空间复杂度为O(n1+n2)(最长不会超过n1+n2),否则就是O(1)的。

官方题解

  • 我的评价是不如我的, 多加点时间开销实现起来会简单很多,即将字符串提前翻转,还能利用到内存的空间连续性,虽然开销稍微增加了,但是理解起来也方便了。

你可能感兴趣的:(leetcode训练,leetcode,算法,职场和发展,c++,数据结构)