以字符串形式输入两个正整数,计算“两数相乘”(不可使用Biginteage等内置库),几种“变相”算法求解。
Python 官网:https://www.python.org/
Free:大咖免费“圣经”教程《 python 完全自学教程》,不仅仅是基础那么简单……
地址:https://lqpybook.readthedocs.io/
自学并不是什么神秘的东西,一个人一辈子自学的时间总是比在学校学习的时间长,没有老师的时候总是比有老师的时候多。
—— 华罗庚
本文质量分:
CSDN质量分查询入口:http://www.csdn.net/qc
给定两个以字符串形式表示的非负整数 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本身。
喜阅博文,偶见代码清奇,CV录之。
class Solution:
def multiply(self, num1: str, num2: str) -> str:
if num1 == "0" or num2 == "0":
return "0"
m, n = len(num1), len(num2)
ans_arr = [0] * (m + n)
for i in range(m - 1, -1, -1):
x = int(num1[i])
for j in range(n - 1, -1, -1):
ans_arr[i + j + 1] += x * int(num2[j])
for i in range(m + n - 1, 0, -1):
ans_arr[i - 1] += ans_arr[i] // 10
ans_arr[i] %= 10
index = 1 if ans_arr[0] == 0 else 0
ans = "".join(str(x) for x in ans_arr[index:])
return ans
class Solution:
def multiply(self, num1: str, num2: str) -> str:
if num1 == "0" or num2 == "0":
return "0" # 两数其一为“0”,乘积为“0”。
m, n = len(num1), len(num2)
ans_arr = [0] * (m + n) # 乘积数位列表,预调乘积数位 len(num1) + len(num2)位。
for i in range(m - 1, -1, -1): # 两层for嵌套求乘积各位数值。
x = int(num1[i])
print()
for j in range(n - 1, -1, -1):
print(x * int(num2[j]))
ans_arr[i + j + 1] += x * int(num2[j])
print(ans_arr)
for i in range(m + n - 1, 0, -1): # 处理各数位进位,得到积的各数位数字。
ans_arr[i - 1] += ans_arr[i] // 10 # 向前进位。
ans_arr[i] %= 10 # 模10得到本数组数字。
print(ans_arr)
index = 1 if ans_arr[0] == 0 else 0 # 如果最高位是零,舍去高位零。
ans = "".join(str(x) for x in ans_arr[index:]) # 拼接非高位“9”外的数位数字(乘积)。
return ans
通过品读佬的代码,且用print()让代码执行过程显形,才完全理解佬的算法:收集两数乘积各数位上的乘积之和,再遍历进位后得到乘积的各数位上的数字,’’.join()拼接输出乘积整数字符串。这算法也算是别具一格了。
通透了佬的算法,我手痒痒地开启了“复刻模式”
我用dict来收集数位乘积,不用预先设备位置,这一点比list好使,dict.get(key, 0)获取dict中key的值进行累加,key不在dict中,则创建key其值赋“0”;用str[i-1]或者list.pop()来让字符串整数颠倒数位,高位数字在后低位在前,方便遍历;用enumerate()来简洁遍历时的下标引用(enumerate可以同时遍历下标和元素)。
题目限定不可以用Biginteger类内置库,且不可以将输入整数字符串直接转换成整型int相乘,也就是要求“手撕”多位数乘法,但并未限定最后结果输出字符串不可以用str转换函数。所以——
class Solution:
def multiply(self, num1: str, num2: str) -> str:
if num1 == "0" or num2 == "0":
return "0" # 两数其一为“0”,乘积为“0”。
num1 = [num1[i-1] for i in range(len(num1), 0, -1)] # 用下标实现整数低位在前。
num2 = list(num2)
num2 = [num2.pop() for i in num2[:]] # 用list.pop()方法模拟堆栈弹出实现整数低位在前。
#input((num1, num2)) # 调试代码显示变量语句。
ans_arr = {} # 乘积数位字典。
for m,i in enumerate(num1):
for n,j in enumerate(num2):
print(m + n, int(i) * int(j)) # 调试用语句,非必需,可以注释掉。
ans_arr[m + n] = ans_arr.get(m + n, 0) + int(i) * int(j)
print(f"\n乘积各数位字典(0为个位,1为十位,2为百位……):\n{ans_arr}") # 调试用语句,非必需,可以注释掉。
return str(sum(value * (10**key) for key,value in ans_arr.items())) # 列表解析出乘积各数位值,求和后转str返回。
class Solution:
def multiply(self, num1: str, num2: str) -> str:
if num1 == "0" or num2 == "0":
return "0" # 两数其一为“0”,乘积为“0”。
num1 = [num1[i-1] for i in range(len(num1), 0, -1)] # 用下标实现整数低位在前。
num2 = list(num2)
num2 = [num2.pop() for i in num2[:]] # 用list.pop()方法模拟堆栈弹出实现整数低位在前。
#input((num1, num2)) # 调试代码显示变量语句。
ans_arr = {} # 乘积数位字典。
for m,i in enumerate(num1):
for n,j in enumerate(num2):
print(m + n, int(i) * int(j)) # 调试用语句,非必需,可以注释掉。
ans_arr[m + n] = ans_arr.get(m + n, 0) + int(i) * int(j)
print(f"\n乘积各数位字典(0为个位,1为十位,2为百位……):\n{ans_arr}") # 调试用语句,非必需,可以注释掉。
ans = []
for key,value in ans_arr.items():
#print(value//10) 代码调试用语句。
if value//10:
ans_arr[key + 1] = ans_arr.get(key+1, 0) + value//10
ans.insert(0, str(value%10))
else:
ans.insert(0, str(value%10))
#print(ans_arr) 代码调试用语句。
#input(ans) #代码调试用语句。
return ''.join(ans) # 列表解析出乘积各数位值,求和后转str返回。
前面代码的主人在博文中提到,“手撕”多位数乘法,实则是模拟我们在学校学到的列竖式计算。那,除了佬的算法外,还可以有“变相”算法:
我们的传统竖式,如果得到的数位乘积不进行进位操作,会是下图的样子。
据上图原理进行两层for遍历,
for i in range(len(num1)-1, -1, -1):
multiple2 = 1 # num2的数位等差初值。
for j in range(len(num1)-1, -1, -1):
print(int(num1[i])*int(num2[j])*multiple1*multiple2)
out += int(num1[i])*int(num2[j])*multiple1*multiple2 # 乘积累加。
multiple2 *= 10 # num2的数位等差自增。
#print(num1[i], num2[j]) # 调试用语句。
multiple1 *= 10 # num1的数位等差自增。
即得示例123×456的九次相乘积的列表,
变量累加或者sum(遍历乘积集合),就得到最后的两个多位整数相乘之积。
变量累加各分项计算乘积
def str_multiply(num1: str, num2: str) -> str:
''' 字符串相乘 '''
out_first = f"\n{'':>8}{num1} × {num2} = "
out = 0 # 乘积初值。
multiple1 = 1 # num1的数位等差初值。
for i in range(len(num1)-1, -1, -1):
multiple2 = 1 # num2的数位等差初值。
for j in range(len(num1)-1, -1, -1):
print(int(num1[i])*int(num2[j])*multiple1*multiple2)
out += int(num1[i])*int(num2[j])*multiple1*multiple2 # 乘积累加。
multiple2 *= 10 # num2的数位等差自增。
#print(num1[i], num2[j]) # 调试用语句。
multiple1 *= 10 # num1的数位等差自增。
return f"\n{out_first}{out}"
def str_multiply4(num1: str, num2: str) -> str:
''' 字符串相乘 '''
out_first = f"\n{'':>8}{num1} × {num2} = "
out = [] # 两数乘积分项列表。
num1, num2 = list(num1), list(num2)
# 列表解析整数数位倒置。
num1 = ''.join([num1.pop() for i in num1[:]])
num2 = ''.join([num2.pop() for i in num2[:]])
multiple1 = 1 # num1的数位等差初值。
for i in num1:
multiple2 = 1 # num2的数位等差初值。
for j in num2:
out.append(int(i)*int(j)*multiple1*multiple2)
multiple2 *= 10 # num2的数位等差自增。
#print(i, j) # 调试代码语句打印。
multiple1 *= 10 # num1的数位等差自增。
print(f"\n分项乘积列表:\n{out}") # 调试代码用显示变量。
out = sum(out)
if not out%10: # 乘积为一位数,直接返回乘积。
return f"{first}{out}\n"
out_s, n = [], 1
while out//(10**n): # 逐位抽取多倍整数的各位数数字。
if n == 1:
out_s.insert(0, str(out%10)) # 取个位。
out_s.insert(0, str(out//(10**n)%10)) # 取十、百、千、万……直到数位全部取完。
n += 1
#input(out_s) # 调试代码用显示变量语句。
return f"\n{out_first}{''.join(out_s)}\n" # 拼接各位数字字符返回乘积数字字符串。
累加内层for得到的乘积,即得到传统竖式计算多位数乘法的一致算法。
def str_multiply3(num1: str, num2: str) -> str:
''' 字符串相乘 '''
out_first = f"\n{'':>8}{num1} × {num2} = "
multiple = {} # 乘积字典,以整数数位等差级别为key。
num1, num2 = list(num1), list(num2)
# 列表解析整数数位倒置。
num1 = ''.join([num1.pop() for i in num1[:]])
num2 = ''.join([num2.pop() for i in num2[:]])
place1 = 1 # 个位数位等差级别。
for i in num1:
place2 = 1
for j in num2:
multiple[place1] = multiple.get(place1, 0) + int(i) * int(j) * place2 # 数位等差级别key(累加数位乘积)。
place2 *= 10 # num2数位等差级别变高一级。
place1 *= 10 # num1数位等差级别变高一级。
print(f"\n数位乘积分项字典:\n{multiple}")
return f"{out_first}{sum([key*value for key,value in multiple.items()])}\n" # 列表解析出乘积求和返回。
(源码较长,点此跳过源码)
#!/sur/bin/nve python
# coding: utf-8
'''
字符串相乘
'''
# CV佬的代码
class Solution:
def multiply(self, num1: str, num2: str) -> str:
if num1 == "0" or num2 == "0":
return "0"
m, n = len(num1), len(num2)
ans_arr = [0] * (m + n)
for i in range(m - 1, -1, -1):
x = int(num1[i])
for j in range(n - 1, -1, -1):
ans_arr[i + j + 1] += x * int(num2[j])
for i in range(m + n - 1, 0, -1):
ans_arr[i - 1] += ans_arr[i] // 10
ans_arr[i] %= 10
index = 1 if ans_arr[0] == 0 else 0
ans = "".join(str(x) for x in ans_arr[index:])
return ans
# 品读佬的代码
class Solution:
def multiply(self, num1: str, num2: str) -> str:
if num1 == "0" or num2 == "0":
return "0" # 两数其一为“0”,乘积为“0”。
m, n = len(num1), len(num2)
ans_arr = [0] * (m + n) # 乘积数位列表,预调乘积数位 len(num1) + len(num2)位。
for i in range(m - 1, -1, -1): # 两层for嵌套求乘积各位数值。
x = int(num1[i])
print()
for j in range(n - 1, -1, -1):
print(x * int(num2[j]))
ans_arr[i + j + 1] += x * int(num2[j])
print(ans_arr)
for i in range(m + n - 1, 0, -1): # 处理各数位进位,得到积的各数位数字。
ans_arr[i - 1] += ans_arr[i] // 10 # 向前进位。
ans_arr[i] %= 10 # 模10得到本数组数字。
print(ans_arr)
index = 1 if ans_arr[0] == 0 else 0 # 如果最高位是零,舍去高位零。
ans = "".join(str(x) for x in ans_arr[index:]) # 拼接非高位“9”外的数位数字(乘积)。
return ans
# 按佬的“思路”改写Python代码
class Solution:
def multiply(self, num1: str, num2: str) -> str:
if num1 == "0" or num2 == "0":
return "0" # 两数其一为“0”,乘积为“0”。
num1 = [num1[i-1] for i in range(len(num1), 0, -1)] # 用下标实现整数低位在前。
num2 = list(num2)
num2 = [num2.pop() for i in num2[:]] # 用list.pop()方法模拟堆栈弹出实现整数低位在前。
#input((num1, num2)) # 调试代码显示变量语句。
ans_arr = {} # 乘积数位字典。
for m,i in enumerate(num1):
for n,j in enumerate(num2):
print(m + n, int(i) * int(j)) # 调试用语句,非必需,可以注释掉。
ans_arr[m + n] = ans_arr.get(m + n, 0) + int(i) * int(j)
print(f"\n乘积各数位字典(0为个位,1为十位,2为百位……):\n{ans_arr}") # 调试用语句,非必需,可以注释掉。
#return str(sum(value * (10**key) for key,value in ans_arr.items())) # 列表解析出乘积各数位值,求和后转str返回。
ans = []
for key,value in ans_arr.items():
#print(value//10) 代码调试用语句。
if value//10:
ans_arr[key + 1] = ans_arr.get(key+1, 0) + value//10
ans.insert(0, str(value%10))
else:
ans.insert(0, str(value%10))
#print(ans_arr) 代码调试用语句。
#input(ans) #代码调试用语句。
return ''.join(ans) # 列表解析出乘积各数位值,求和后转str返回。
def str_multiply(num1: str, num2: str) -> str:
''' 字符串相乘 '''
out_first = f"\n{'':>8}{num1} × {num2} = "
out = 0 # 乘积初值。
multiple1 = 1 # num1的数位等差初值。
for i in range(len(num1)-1, -1, -1):
multiple2 = 1 # num2的数位等差初值。
for j in range(len(num1)-1, -1, -1):
print(int(num1[i])*int(num2[j])*multiple1*multiple2)
out += int(num1[i])*int(num2[j])*multiple1*multiple2 # 乘积累加。
multiple2 *= 10 # num2的数位等差自增。
#print(num1[i], num2[j]) # 调试用语句。
multiple1 *= 10 # num1的数位等差自增。
return f"\n{out_first}{out}"
def str_multiply(num1: str, num2: str) -> str:
''' 字符串相乘 '''
out_first = f"\n{'':>8}{num1} × {num2} = "
out = [] # 两数乘积分项列表。
num1, num2 = list(num1), list(num2)
# 列表解析整数数位倒置。
num1 = ''.join([num1.pop() for i in num1[:]])
num2 = ''.join([num2.pop() for i in num2[:]])
multiple1 = 1 # num1的数位等差初值。
for i in num1:
multiple2 = 1 # num2的数位等差初值。
for j in num2:
out.append(int(i)*int(j)*multiple1*multiple2)
multiple2 *= 10 # num2的数位等差自增。
#print(i, j) # 调试代码语句打印。
multiple1 *= 10 # num1的数位等差自增。
print(f"\n分项乘积列表:\n{out}") # 调试代码用显示变量。
out = sum(out)
if not out%10: # 乘积为一位数,直接返回乘积。
return f"{first}{out}\n"
out_s, n = [], 1
while out//(10**n): # 逐位抽取多倍整数的各位数数字。
if n == 1:
out_s.insert(0, str(out%10)) # 取个位。
out_s.insert(0, str(out//(10**n)%10)) # 取十、百、千、万……直到数位全部取完。
n += 1
#input(out_s) # 调试代码用显示变量语句。
return f"\n{out_first}{''.join(out_s)}\n" # 拼接各位数字字符返回乘积数字字符串。
def str_multiply(num1: str, num2: str) -> str:
''' 字符串相乘 '''
out_first = f"\n{'':>8}{num1} × {num2} = "
multiple = {} # 乘积字典,以整数数位等差级别为key。
num1, num2 = list(num1), list(num2)
# 列表解析整数数位倒置。
num1 = ''.join([num1.pop() for i in num1[:]])
num2 = ''.join([num2.pop() for i in num2[:]])
place1 = 1 # 个位数位等差级别。
for i in num1:
place2 = 1
for j in num2:
multiple[place1] = multiple.get(place1, 0) + int(i) * int(j) * place2 # 数位等差级别key(累加数位乘积)。
place2 *= 10 # num2数位等差级别变高一级。
place1 *= 10 # num1数位等差级别变高一级。
print(f"\n数位乘积分项字典:\n{multiple}")
return f"{out_first}{sum([key*value for key,value in multiple.items()])}\n" # 列表解析出乘积求和返回。
if __name__ == '__main__':
sol = Solution()
print(sol.multiply('123', '456'))
print(str_multiply('5', '3'))
print(str_multiply('123', '456'))
我的HOT博:
本次共计收集 188 篇博文笔记信息,平均阅读量 1517 。已生成阅读量大于3000的 17 篇笔记索引链接。数据采集于 2023-03-30 22:27:21 完成,用时 4 分 57.30 秒。
精品文章:
来源:老齐教室
◆ Python 入门指南【Python 3.6.3】
好文力荐:
全栈领域优质创作者——寒佬(还是国内某高校学生)博文“非技术文—关于英语和如何正确的提问”,“英语”和“会提问”是学习的两大利器。
【8大编程语言的适用领域】先别着急选语言学编程,先看它们能干嘛
靠谱程序员的好习惯
CSDN实用技巧博文: