算法练习:力扣43题——字符串相乘

132 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情

力扣题解

力扣43题:leetcode.cn/problems/mu…

字符串相乘——计算每个数位的值

给定两个以字符串形式表示的非负整数 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本身。

思路

题目中要求了不能使用 BigInteger 库或直接将输入转换为整数,并且字符串的长度上限是200,也很难转化成整数进行计算。因此,这里提供一种利用数位进行计算的思路。

如何计算两个数相乘的个位数的数字?

例如 123 x 456 ,很容易看出,个位数一定是8,因为 3 x 6 = 18 ,所以个位数一定是8

那么,如何计算两个数相乘的十位上的数字?

还是 123 x 456 ,则计算十位上的数字,需要数字A的十位与数字B的个位相乘,加上数字B的十位与数字A的个位相乘,再加上上一个数位(这里是个位)相乘的进位(3 x 6 = 18,进位为1),得到和 Sum,则 Sum%10 即为十位上的数字值,此时 Sum/10 为十位的进位,可以用计算百位上的数字值。

核心思路:

基于上述思路,计算百位上的数字时,则需要考虑个位*百位十位*百位;同理,计算千位时,需要考虑个位*千位十位*百位;以此类推,万位、十万位...均是类似的计算方法,这里的个位对应字符串中的最后一个元素。

注意事项:

  • 字符串需要区分长短,方便循环时计算

详细代码+注释:

/**
     * 字符串相乘,返回字符串类型的成绩结果
     *
     * @param num1 字符串类型的整数1
     * @param num2 字符串类型的整数2
     * @return 整数1和整数2的乘积,字符串类型
     * 方法:计算每个数位的值
     */
    public String multiply(String num1, String num2) {
        if (num1 == null || num2 == null || "".equals(num1) || "".equals(num2)) {
            return "";
        }
        // 短字符串和长字符串对应的数组
        char[] shortArr, longArr;
        if (num1.length() > num2.length()) {
            shortArr = num2.toCharArray();
            longArr = num1.toCharArray();
        } else {
            shortArr = num1.toCharArray();
            longArr = num2.toCharArray();
        }
        if (shortArr[0] == '0' || longArr[0] == '0') {
            return "0";
        }
        // 长短字符数组长度
        int len1 = shortArr.length, len2 = longArr.length;
        int len = len1 + len2;
        // 临时结果,存储每个数位上对应的数字
        int[] res = new int[len];
        // 当前位、进位值
        int currDigit = 0, carry = 0;
        // 计算每一个数位上的和,i起始对应个位
        for (int i = 0; i < len; i++) {
            // 计算数位和
            int sum = 0;
            // i+2表示计算第i位(i从0开始)时长短数组中元素位置的和,例如计算“123”和“456”相乘时,计算56088中的第二个8时(i=1),则需要计算2*6+3*5+1==28,(1是3*6=18的进位),个位8即为当前位的值
            // 这里需要考虑i+2是超过了短数组的长度,这里取len1+1表明,下面的j可以取len1
            int end = Math.min(i + 2, len1 + 1);
            for (int j = 1; j < end; j++) {
                // 满足短数组长度要求的同时,也要满足长数组的长度要求
                if ((i + 2 - j) <= len2) {
                    sum += (shortArr[len1 - j] - '0') * (longArr[len2 - (i + 2 - j)] - '0');
                }
            }
            sum += carry;
            // 个位值,即,当前位置的数字
            currDigit = sum % 10;
            // 进位
            carry = sum / 10;
            res[i] = currDigit;
        }
        int index = res.length - 1;
        // 去0
        while (index >= 0 && res[index] == 0) {
            index--;
        }
        // 得到最终结果,倒序遍历
        StringBuilder sb = new StringBuilder();
        for (int i = index; i >= 0; i--) {
            sb.append(res[i]);
        }
        return sb.toString();
    }