Python面试宝典第35题:字符串相乘

CSDN 2024-09-15 14:05:01 阅读 67

题目

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

        注意:不能使用任何内置的BigInteger库或直接将输入转换为整数。

        备注:

        (1)1 <= num1.length, num2.length <= 200。

        (2)num1和num2只能由数字组成。

        (3)num1和num2都不包含任何前导零,除了数字0本身。

        示例 1:

<code>输入: num1 = "2", num2 = "3"

输出: "6"

        示例 2:

输入: num1 = "123", num2 = "456"

输出: "56088"

手动实现乘法

        使用手动实现乘法来解决本题是一种直观且有效的方法,它模拟了我们在纸上进行大数乘法的方式。求解本题的主要步骤如下。

        1、初始化。创建一个结果数组result用于存储乘积的每一位。

        2、遍历乘法。从右到左遍历num1的每一位,对于num1的每一位,从右到左遍历num2的每一位。

        3、计算乘积。计算每一位的乘积,并加上进位。

        4、更新进位。更新进位,并将结果存入result数组。

        5、处理进位。遍历完成后,处理最后一次进位,并将result数组转换为字符串。

        根据上面的算法步骤,我们可以得出下面的示例代码。

<code>def string_multiply_manually(num1, num2):

result = [0] * (len(num1) + len(num2))

# 遍历num1的每一位

for i in range(len(num1) - 1, -1, -1):

n1 = int(num1[i])

# 遍历num2的每一位

for j in range(len(num2) - 1, -1, -1):

n2 = int(num2[j])

# 计算乘积并加上进位

product = n1 * n2 + result[i + j + 1]

# 更新进位

carry = product // 10

result[i + j + 1] = product % 10

# 更新当前位置的值

result[i + j] += carry

# 处理前导零

i = 0

while i < len(result) and result[i] == 0:

i += 1

# 转换成字符串

return ''.join(map(str, result[i:]))

print(string_multiply_manually("2", "3"))

print(string_multiply_manually("123", "456"))

Karatsuba算法

        Karatsuba算法是由著名的俄罗斯数学家Karatsuba发明的,它以其在快速乘法算法领域的工作而闻名。Karatsuba算法利用了分治的思想,通过将大数分解为较小的部分来减少乘法的次数。其算法的主要特点如下:

        1、将两个大数分别拆分为高位和低位两个部分。

        2、利用公式 xy = (a * 10^n + b) * (c * 10^n + d) = ac * 10^(2n) + ((ad + bc) * 10^n) + bd 来计算乘法结果。其中a、b、c、d分别表示大数的高位和低位部分,n表示大数的位数一半的位置。

        3、通过递归地应用该算法,可以有效地减少所需的乘法次数。

        使用Karatsuba算法求解本题的主要步骤如下。

        1、基础情况。如果任意一个数字的长度小于等于1,则直接返回它们的乘积。

        2、分割数字。将两个数字分割成高位和低位,为后面的步骤做准备。

        3、递归计算。递归地计算高位乘积、低位乘积和交叉乘积。

        4、组合结果。利用上述结果,计算出最终的乘积。

        根据上面的算法步骤,我们可以得出下面的示例代码。

def string_multiply_by_karatsuba(num1, num2):

def str_to_int(s):

return int(s)

def int_to_str(n):

return str(n)

# 基本情况

if num1 == "0" or num2 == "0":

return "0"

if len(num1) < 10 or len(num2) < 10:

return int_to_str(str_to_int(num1) * str_to_int(num2))

# 分割数字

n = max(len(num1), len(num2))

half = n // 2

high1 = num1[:half]

low1 = num1[half:]

high2 = num2[:half]

low2 = num2[half:]

# 递归计算

z0 = string_multiply_by_karatsuba(low1, low2)

z1 = string_multiply_by_karatsuba((str_to_int(low1) + str_to_int(high1)),

(str_to_int(low2) + str_to_int(high2)))

z2 = string_multiply_by_karatsuba(high1, high2)

# 计算最终结果

result = int_to_str(str_to_int(z2) * (10 ** (2 * half)) +

((str_to_int(z1) - str_to_int(z2) - str_to_int(z0)) *

(10 ** half)) + str_to_int(z0))

return result

print(string_multiply_by_karatsuba("2", "3"))

print(string_multiply_by_karatsuba("123", "456"))

总结

        手动实现乘法时,对于两个长度为n的数字,需要遍历每一个数字位,因此时间复杂度为O(n^2)。空间复杂度为O(n),因为需要一个长度为2n的数组来保存乘积的结果。手动实现乘法的概念比较直观,容易理解和实现。但对于非常大的数字,时间复杂度较高,效率较低。

        Karatsuba算法通过递归地将大数分解为较小的部分来减少乘法次数,其时间复杂度大约为O(n^log2(3)) = O(n^1.585),这比传统的O(n^2)更高效。对于较大的数字,Karatsuba算法比传统的乘法更快。但其实现更为复杂,需要理解递归和分治的概念。

        实际上,快速傅立叶变换 (Fast Fourier Transform, 即FFT) 也可以用来高效地计算大数乘法。但其实现复杂性高,需要较强的数学背景支持,这里就不再赘述了。

💡 需要《Python面试宝典》完整源码的大佬们,可订阅专栏后,搜索



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。