📅  最后修改于: 2023-12-03 15:42:21.644000             🧑  作者: Mango
欢迎来到门|门 IT 2006年第35题!这是一道面向程序员的挑战题目,需要你发挥你的编程能力和思维能力。下面让我们来看一下问题描述和要求。
给定两个数字字符串 $s_1$ 和 $s_2$($s_1,s_2$长度 $\leq 10^5$),请你计算出它们相乘的结果,并以字符串的形式返回。
实现一个函数 multiply(s1:str, s2:str) -> str
,其中:
s1
和 s2
表示两个数字字符串,不包含前导零。示例1:
输入:s1 = "123456789", s2 = "987654321"
输出:"121932631137021795832388570617"
示例2:
输入:s1 = "2", s2 = "3"
输出:"6"
此处建议给出一些实现思路或者提示,此题可以参考以下算法:
大多数程序员第一眼看到本题难点可能就在于如何实现两个超长数字的乘积运算,所以我们在这里先介绍一下大整数乘法的基本思路。
大整数乘法是用于计算超长数字的乘积的一种算法。通常情况下,我们把两个数字分别拆分为对半的两部分,然后分别计算每一部分的乘积,接着将所得的乘积拼接再进行一些进位等计算,最后得到最终结果。这种方法的复杂度大约是 $O(n^2)$ 的,但是如果使用数论中的卷积算法,那么复杂度就能降为 $O(n \log n)$。
卷积算法是大多数处理信号的算法中最常用的一种。如果把输入的两个数字序列视为长度为n的向量,则两个数字序列的卷积就是它们的点积,也就是所有对应位置上的数的乘积之和。将卷积运算的复杂度降为 $O(n \log n)$ 就变得很重要了,因为大数据运算的时间复杂度可控性对效率的影响很大。
基于上述两个算法思路,实现起来可能会有一些细节问题,需要注意一下。同时,如果需要学习或者复习卷积算法,可以自行搜索相关课程或资料。
def multiply(s1:str, s2:str) -> str:
def fft(a, n, sign: int):
if n == 1:
return a
a0 = [a[i] for i in range(0, n, 2)]
a1 = [a[i] for i in range(1, n, 2)]
y0 = fft(a0, n // 2, sign)
y1 = fft(a1, n // 2, sign)
omega = complex(1, 0)
delta = complex(math.cos(sign * 2 * math.pi / n), math.sin(sign * 2 * math.pi / n))
res = [0] * n
for k in range(n // 2):
res[k] = y0[k] + omega * y1[k]
res[k + n // 2] = y0[k] - omega * y1[k]
omega *= delta
return res
def inv_fft(a, n):
res = fft(a, n, -1)
return [int((x / n).real + 0.5) for x in res]
# 转换为多项式
n1, n2 = len(s1), len(s2)
n, m = 2 ** math.ceil(math.log2(n1 + n2)), 10
a = [int(s1[i]) for i in range(n1)]
b = [int(s2[i]) for i in range(n2)]
a, b = a[::-1], b[::-1]
a = a + [0] * (n1 - len(a))
b = b + [0] * (n2 - len(b))
# FFT 算法计算多项式,a 和 b 都是系数
A = fft(a, n, 1)
B = fft(b, n, 1)
## 题解
本题涉及到了大数相乘和卷积算法,对于初学者来说难度较大,需要一定的数学基础和编程能力。其中卷积算法是 FFT(快速傅里叶变换)实现的,需要对复杂数、FFT算法的原理、多项式及其运算符号、卷积算法的套路等有一定的了解。如果不熟练,建议先学习一些相关基础知识。