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

39 篇文章 1 订阅

一、示例

示例 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)或直接将输入转换为整数来处理。

三、解题思路

对于比较小的数字,做运算可以直接使用编程语言提供的运算符,但是如果相乘的两个因数非常大,语言提供的数据类型可能就会溢出。一种替代方案就是,运算数以字符串的形式输入,然后模仿我们小学学习的乘法算术过程计算出结果,并且也用字符串表示。

需要注意的是,num1 和 num2 可以非常长,所以不可以把他们直接转成整型然后运算,唯一的思路就是模仿我们手算乘法。

比如说我们手算 123 × 45,应该会这样计算:

在这里插入图片描述
计算 123 × 5,再计算 123 × 4,最后错一位相加。这个流程恐怕小学生都可以熟练完成,但是你是否能「把这个运算过程进一步机械化」,写成一套算法指令让没有任何智商的计算机来执行呢?

你看这个简单过程,其中涉及乘法进位,涉及错位相加,还涉及加法进位;而且还有一些不易察觉的问题,比如说两位数乘以两位数,结果可能是四位数,也可能是三位数,你怎么想出一个标准化的处理方式?这就是算法的魅力,如果没有计算机思维,简单的问题可能都没办法自动化处理。

首先,我们这种手算方式还是太「高级」了,我们要再「低级」一点,123 × 5 和 123 × 4 的过程还可以进一步分解,最后再相加:
在这里插入图片描述
现在 123 并不大,如果是个很大的数字的话,是无法直接计算乘积的。我们可以用一个数组在底下接收相加结果:

在这里插入图片描述
整个计算过程大概是这样,有两个指针 i,j 在 num1 和 num2 上游走,计算乘积,同时将乘积叠加到 res 的正确位置:
在这里插入图片描述
现在还有一个关键问题,如何将乘积叠加到 res 的正确位置,或者说,如何通过 i,j 计算 res 的对应索引呢?

其实,细心观察之后就发现,num1[i] 和 num2[j] 的乘积对应的就是 res[i+j] 和 res[i+j+1] 这两个位置。

在这里插入图片描述

四、Demo

class Solution {
    public static void main(String[] args) {
        String s1 = "123";
        String s2 = "45";
        System.out.println(Solution.multiply(s1, s2));
        System.out.println(Solution.multiply(s1, s2).getClass().getName());
    }

    static String multiply(String num1, String num2) {
        // 参与乘法的一方有"0", 结果返回"0"
        if (num1.equals("0") || num2.equals("0")) {
            return "0";
        }

        int length1 = num1.length();
        int length2 = num2.length();
        // 结果最多为 length1 + length2 位数, 即 0 至 length1 + length2 - 1
        int[] res = new int[length1 + length2];

        // 从个位数开始逐位相乘
        for (int i = length1 - 1; i >= 0; i--) {
            for (int j = length2 - 1; j >= 0; j--) {
                // 取出String中的单个字符, 作乘法, 要减去字符'0'的ASCII码48
                int mul = (num1.charAt(i) - '0') * (num2.charAt(j) - '0');
                // 乘积在 res 对应的索引位置
                int index1 = i + j, index2 = i + j + 1;
                // 把余数和进位叠加到res数组上
                int sum = mul + res[index2];
                    // 求余数的时候需要在上一步把低位部分加上
                res[index2] = sum % 10;
                    // 算进位, 不需要考虑当前循环新增的低位和高位部分
                res[index1] += sum / 10;
            }
        }

        // for循环结束以后的res数组结果前缀中有可能存在0(未使用的位)
        int i = 0;
        // 确认在前缀中有几位是0
        while (i < res.length && res[i] == 0) {
            i++;
        }

        // 将计算结果转化成字符串
        StringBuffer str = new StringBuffer();
        for (; i < res.length; i++) {
            str.append("" + res[i]);
        }

        return str.toString();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cry丶

如果觉得有帮助的打个赏吧。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值