每日一恋 - LeetCode 43. Multiply Strings(字符串相乘)

题目描述

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

分析

此题是一道经典的题目,曾经被华为、腾讯等众多公司作为笔试、面试题,该题有一定的难度,如果没有准备过则需要花一定时间去写的,而且该题有一定技巧的,如果没设计好结构直接解析字符串硬乘,然后进位相加则困难很大。大数相乘法主要有模拟手工计算的普通大数相乘法、分治算法和FFT算法等三种方法,面试中只有会用普通大数相乘法解决就足够了,下面我将分析下普通大数相乘法。

解题思路

普通相乘是按位相乘,然后将相应的位相加,最后考虑进位。

例如:

A = 17 = 1 * 10 + 7 = (7,1) 转换成十进制的幂表示法,幂次是从低位到高位
B = 25 = 2 * 10 + 5 = (5,2)
C = A * B = (7 * 5, 1 * 5 + 2 * 7, 1 * 2) = (35, 19 ,2)
进位处理过程: (35, 19, 2) = (5, 22, 2) = (5, 2, 4) = 425

这里写图片描述

处理的整体步骤为:
- 将字符串按位相乘,并加结果放到 r e s u l t [ i + j ] 中(相乘相加的过程)
- 将 r e s u l t [ i + j ] 结果按低位到高位处理进位
- 将处理进位后的结果以字符串形式表示出来

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

    StringBuilder sb = new StringBuilder();
    int a = num1.length();
    int b = num2.length();
    int[] nums = new int[a + b - 2 + 1];

    for (int i = 0 ; i < a ; i ++) {
        for (int j = 0 ; j < b ; j ++) {
            // 按位相乘并保存到 i + j 处
            nums[i + j] += Integer.valueOf(num1.charAt(i) - '0') * Integer.valueOf(num2.charAt(j) - '0');
        }
    }

    // 进位处理,将结果转换成字符串表示
    int carry = 0;
    for (int i = nums.length - 1 ; i >= 0 ; i --) {
        int tmp = nums[i] + carry;
        sb.append(tmp % 10);
        carry = tmp / 10;
    }
    // 处理最高位的进位
    while (carry > 0) {
        sb.append(carry % 10);
        carry = carry / 10;
    }
    // 反转字符串
    return sb.reverse().toString();
}
  • 时间复杂度:该算法使用了两层循环,循环次数分布为 m(数1的长度)和 n(数2的长度),因此时间复杂度为O(m * n)。
  • 空间复杂度:该算法占用的空间复杂度为 O(m + n)。

猜你喜欢

转载自blog.csdn.net/smartnijun/article/details/81739994