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 本身。
不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来

题目分析

跟“字符串相加”类似,这里我们要处理的,也是大整数的相乘问题。
思路也可以非常类似:我们借鉴数学中“竖式乘法”的规则,用num1分别去乘num2的每一位数字,最后再用AddStrings将乘出的结果全部叠加起来就可以了。
在这里插入图片描述

具体代码实现

public class MultiplyStrings {
    public String multiply(String num1, String num2) {
        if ( num1.equals("0") || num2.equals("0") ) return "0";
        String result = "0";

        // 遍历num2的每个数位,逐个与num1相乘
        for ( int i = num2.length() - 1; i >= 0; i-- ){
            int carry = 0;
            StringBuffer curRes = new StringBuffer();
            for ( int j = 0; j < num2.length() - 1 - i; j++ ){
                curRes.append("0");
            }

            int y = num2.charAt(i) - '0';

            // 遍历num1的每一位数,跟y相乘
            for ( int j = num1.length() - 1; j >= 0; j-- ){
                int x = num1.charAt(j) - '0';
                int product = x * y + carry; 
                curRes.append(product % 10);
                carry = product / 10;
            }
            if (carry != 0) curRes.append(carry);
            AddStrings addStrs = new AddStrings();
            result = addStrs.addStrings(result, curRes.reverse().toString());
        }
        return result;
    }
}

时间复杂度
时间复杂度:O(mn+n^2),其中 m 和 n 分别是 num1 和 num2的长度。
做计算的时候,外层需要从右往左遍历num2,而对于num2的每一位,都需要和 num1的每一位计算乘积,因此计算乘积的总次数是 mn。字符串相加操作共有 n次,每次相加的字符串长度最长为 m+n,因此字符串相加的时间复杂度是 O(mn+n^2)。总时间复杂度是 O(mn+n^2)。

空间复杂度:O(m+n)。空间复杂度取决于存储中间状态的字符串,由于乘积的最大长度为 m+n,因此存储中间状态的字符串的长度不会超过 m+n。

算法优化

我们看到计算过程中,用到了太多的字符串相加操作,调用addStrings方法时又需要遍历字符串的每一位,这个过程显得有些繁琐。能不能用其它的方法进行简化呢?

我们发现,m位数乘以n位数,结果最多就是m+n位;所以我们可以用一个m+n长度的数组来保存计算结果。
而且,某两个数位相乘,num1[i] x num2[j] 的结果(定义为两位数,一位数的话前面补0),其第一位位于 result[i+j],第二位位于 result[i+j+1]。
在这里插入图片描述

根据上面的思路,我们可以遍历num1和num2中的每一位数,相乘后叠加到result的对应位上就可以了。

代码实现

public String multiply(String num1, String num2) {
    if ( num1.equals("0") || num2.equals("0") ) return "0";
    int[] resultArr = new int[num1.length() + num2.length()];

    // 遍历num1和num2,逐位计算乘积,填入结果数组中
    for ( int i = num1.length() - 1; i >= 0; i-- ){
        int x = num1.charAt(i) - '0';
        for ( int j = num2.length() - 1; j >= 0; j-- ){
            int y = num2.charAt(j) - '0';
            int product = x * y;
            int temp = resultArr[i+j+1] + product;
            resultArr[i+j+1] = temp % 10;
            resultArr[i+j] += temp / 10;
        }
    }
    StringBuffer result = new StringBuffer();
    int start = resultArr[0] == 0 ? 1 : 0; 
    for ( int i = start; i < resultArr.length; i++ ){
        result.append(resultArr[i]);
    }
    return result.toString();
}

复杂度分析

时间复杂度:O(mn),其中 m 和 n 分别是 num1 和 num2的长度。需要计算num1 的每一位和 num2的每一位的乘积。
空间复杂度:O(m+n),需要创建一个长度为 m+n 的数组存储乘积。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值