leetcode题解之43. 字符串相乘

Posted 刷题之路1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode题解之43. 字符串相乘相关的知识,希望对你有一定的参考价值。

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

示例 1:

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

示例 2:

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

说明:

  1. num1 和 num2 的长度小于110。
  2. num1 和 num2 只包含数字 0-9
  3. num1 和 num2 均不以零开头,除非是数字 0 本身。
  4. 不能使用任何标准库的大数类型(比如 BigInteger)直接将输入转换为整数来处理

方法一:普通竖式

思路

竖式运算思想,以 num1123num2456 为例分析:

技术图片

遍历 num2 每一位与 num1 进行相乘,将每一步的结果进行累加。

注意:

  • num2 除了第一位的其他位与 num1 运算的结果需要 补0
  • 计算字符串数字累加其实就是 415. 字符串相加

实现

class Solution {
    /**
    * 计算形式
    *    num1
    *  x num2
    *  ------
    *  result
    */
    public String multiply(String num1, String num2) {
        if (num1.equals("0") || num2.equals("0")) {
            return "0";
        }
        // 保存计算结果
        String res = "0";
    <span class="hljs-comment">// num2 逐位与 num1 相乘</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = num2.length() - <span class="hljs-number">1</span>; i &gt;= <span class="hljs-number">0</span>; i--) {
        <span class="hljs-keyword">int</span> carry = <span class="hljs-number">0</span>;
        <span class="hljs-comment">// 保存 num2 第i位数字与 num1 相乘的结果</span>
        StringBuilder temp = <span class="hljs-keyword">new</span> StringBuilder();
        <span class="hljs-comment">// 补 0 </span>
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>; j &lt; num2.length() - <span class="hljs-number">1</span> - i; j++) {
            temp.append(<span class="hljs-number">0</span>);
        }
        <span class="hljs-keyword">int</span> n2 = num2.charAt(i) - <span class="hljs-string">‘0‘</span>;
        
        <span class="hljs-comment">// num2 的第 i 位数字 n2 与 num1 相乘</span>
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> j = num1.length() - <span class="hljs-number">1</span>; j &gt;= <span class="hljs-number">0</span> || carry != <span class="hljs-number">0</span>; j--) {
            <span class="hljs-keyword">int</span> n1 = j &lt; <span class="hljs-number">0</span> ? <span class="hljs-number">0</span> : num1.charAt(j) - <span class="hljs-string">‘0‘</span>;
            <span class="hljs-keyword">int</span> product = (n1 * n2 + carry) % <span class="hljs-number">10</span>;
            temp.append(product);
            carry = (n1 * n2 + carry) / <span class="hljs-number">10</span>;
        }
        <span class="hljs-comment">// 将当前结果与新计算的结果求和作为新的结果</span>
        res = addStrings(res, temp.reverse().toString());
    }
    <span class="hljs-keyword">return</span> res;
}

<span class="hljs-comment">/**
 * 对两个字符串数字进行相加,返回字符串形式的和
 */</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">addStrings</span><span class="hljs-params">(String num1, String num2)</span> </span>{
    StringBuilder builder = <span class="hljs-keyword">new</span> StringBuilder();
    <span class="hljs-keyword">int</span> carry = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = num1.length() - <span class="hljs-number">1</span>, j = num2.length() - <span class="hljs-number">1</span>;
         i &gt;= <span class="hljs-number">0</span> || j &gt;= <span class="hljs-number">0</span> || carry != <span class="hljs-number">0</span>;
         i--, j--) {
        <span class="hljs-keyword">int</span> x = i &lt; <span class="hljs-number">0</span> ? <span class="hljs-number">0</span> : num1.charAt(i) - <span class="hljs-string">‘0‘</span>;
        <span class="hljs-keyword">int</span> y = j &lt; <span class="hljs-number">0</span> ? <span class="hljs-number">0</span> : num2.charAt(j) - <span class="hljs-string">‘0‘</span>;
        <span class="hljs-keyword">int</span> sum = (x + y + carry) % <span class="hljs-number">10</span>;
        builder.append(sum);
        carry = (x + y + carry) / <span class="hljs-number">10</span>;
    }
    <span class="hljs-keyword">return</span> builder.reverse().toString();
}

}

复杂度分析

  • 时间复杂度:O(M N)。M,NM,N 分别为 num1num2 的长度。
  • 空间复杂度:O(M+N)。用于存储计算结果。

方法二:优化竖式

该算法是通过两数相乘时,乘数某位与被乘数某位相乘,与产生结果的位置的规律来完成。具体规律如下:

  • 乘数 num1 位数为 MM,被乘数 num2 位数为 NNnum1 x num2 结果 res 最大总位数为 M+N
  • num1[i] x num2[j] 的结果为 tmp(位数为两位,"0x","xy"的形式),其第一位位于 res[i+j],第二位位于 res[i+j+1]

结合下图更容易理解

技术图片

class Solution {
    public String multiply(String num1, String num2) {
        if (num1.equals("0") || num2.equals("0")) {
            return "0";
        }
        int[] res = new int[num1.length() + num2.length()];
        for (int i = num1.length() - 1; i >= 0; i--) {
            int n1 = num1.charAt(i) - ‘0‘;
            for (int j = num2.length() - 1; j >= 0; j--) {
                int n2 = num2.charAt(j) - ‘0‘;
                int sum = (res[i + j + 1] + n1 * n2);
                res[i + j + 1] = sum % 10;
                res[i + j] += sum / 10;
            }
        }
    StringBuilder result = <span class="hljs-keyword">new</span> StringBuilder();
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; res.length; i++) {
        <span class="hljs-keyword">if</span> (i == <span class="hljs-number">0</span> &amp;&amp; res[i] == <span class="hljs-number">0</span>) <span class="hljs-keyword">continue</span>;
        result.append(res[i]);
    }
    <span class="hljs-keyword">return</span> result.toString();
}

}

https://www.jianshu.com/p/e9c375775727

复杂度分析

  • 时间复杂度:O?(?MN?)O*(*M N*)M,NM,N 分别为 num1num2 的长度。
  • 空间复杂度:O?(M+N)O*(M+N)。用于存储计算结果。

算法比较

算法 提交结果 执行用时 内存消耗 语言
普通竖式 通过 48 ms 43.8 MB Java
优化竖式 通过 4 ms 36.6 MB Java

虽然两者时间复杂度和空间复杂度相同,但优化竖式执行速度提高很明显,普通竖式耗时主要还是对每步计算的字符串相加这个过程。



以上是关于leetcode题解之43. 字符串相乘的主要内容,如果未能解决你的问题,请参考以下文章

精选力扣500题 第72题 LeetCode 43. 字符串相乘c++/java详细题解

[LeetCode]415. 字符串相加43. 字符串相乘

《LeetCode之每日一题》:123.字符串相乘

LeetCode 43. 字符串相乘(Multiply Strings)

LeetCode 43 字符串相乘

Python描述 LeetCode 43. 字符串相乘