[leetcode每日一题2020/8/13]43. 字符串相乘

题目来源于leetcode,解法和思路仅代表个人观点。传送门
难度:中等
用时:02:00:00 (想法有点多,矛盾了好久)

题目

给定两个以字符串形式表示的非负整数 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)或直接将输入转换为整数来处理。

思路

首先呢,想到两种做法。
(1)采用正常做乘法的逻辑。一个数的每位,乘上另一个数,然后相加。
(2)把【一个数】加上 自己 的【另一个数】次。


不管哪种算法,大数相加,这个方法,一定要有。


虽然先是想到了(1),但是一开始觉得(1)有点慢。然后就往(2)想了。那就先说说(2)。

那么,如果考虑(2)的话,可以利用【求幂】的思想。
d p [ i ] = d p [ i / 2 ] + d p [ i / 2 ] dp[i] = dp[i/2] + dp[i/2] dp[i]=dp[i/2]+dp[i/2]
类似这种。
但是这种方法尝试了一下过后发现有几个问题。
(1)这个数组,需要很大。可能需要log(10110)(题目条件)。实在太大。
(2)字符串比较难进行 除2 操作。
经过一番尝试,最终还是回到了(1)


那么,如果考虑(1)。任选一个数为乘数,或被乘数。

  1. 可以先计算出0~9 * num1(或num2)的值(字符串)存到一个数组中。这里就可以采用(2)的思想了。
  2. 接着,把num2的每位上num1后(从上面的数组取值)的结果存起来,在结果后面加上"0"(依次递增)(StringBuilder.append)。
  3. 把这些结果相加(大数相加)

代码

class Solution {
    String[] record = new String[10];
    public String multiply(String num1, String num2) {
        if(num1.length()==1 || num2.length()==1){
            if(num1.charAt(0)=='0' || num2.charAt(0)=='0'){
                return "0";
            }
        }
        //给record赋值,时间复杂度是O(n/2)=O(n)
        record[0] = "0";
        record[1] = num1;
        //时间复杂度是O(10)=O(1)
        for(int i=2;i<record.length;i++){
            if(i%2 == 1){
                record[i] = add(add(record[i/2],record[i/2]),num1);
            }else{
                record[i] = add(record[i/2],record[i/2]);
            }
        }
        StringBuilder[] sum = new StringBuilder[num2.length()];
        
        //时间复杂度是O(m*n)
        for(int i=0,j=num2.length()-1;j>=0;i++,j--){
            //bit在0~9之间
            int bit = num2.charAt(j) - '0';
            sum[j] = new StringBuilder();
            sum[j].append(record[bit]);
            for(int k=0;k<i;k++){
                sum[j].append("0");
            }
        }
        
        //时间复杂度是O(m*(m+n))
        String ans = "0";
        for(int i=0;i<sum.length;i++){
            ans = add(sum[i].toString(),ans);
        }

        return ans;
    }
    //两个数相加,时间复杂度是O(Max{n,m})
    public String add(String num1,String num2){
        StringBuilder ans = new StringBuilder();
        int carry = 0;
        int bitSumNum = 0;
        char bitSumChar = '0';
        for(int i=num1.length()-1,j=num2.length()-1 ;i>=0||j>=0 ;i--,j--){
            //取出一位
            int n1 = i>=0?num1.charAt(i)-'0' : 0;
            int n2 = j>=0?num2.charAt(j)-'0' : 0;
            //本位和
            bitSumNum = n1 + n2 + carry;
            //进位
            if(bitSumNum >= 10){
                carry = 1;
                bitSumNum %= 10;
            }else{
                carry = 0;
            }
            bitSumChar = (char)(bitSumNum + '0');
            ans.append(bitSumChar);
        }
        //最后一个进位
        if(carry==0){
            return ans.reverse().toString();
        }
        return ans.append('1').reverse().toString();
    }
}

算法复杂度

时间复杂度: O(n*m + m2 + n)。其中n,m为字符串长度。(大概) 计算num1与0~9相乘需要O(n)。计算两个相加需要O(max{n,m})。计算num1乘num2需要O(n*m)。计算每次乘积的和需要O(m* (n + m) ) 。
空间复杂度: O(n+(m+n)*m)。其中n,m为字符串长度。存放num1与0~9相乘的结果需要O(n)。存放num1乘num2的和需要长度为m的数组,数组每项长度为m+n。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值