数字字符串的加法与乘法
1.数字字符串加法
给定两个长度可以上千上万的数字字符串s1, s2,把它们按数值相加,将结果以字符串形式返回
如"123" + "123" = "246"
这个实现是比较基础的,我们【模拟竖式加法】,从低位到高位取对应字符,转为int相加,一步一步模拟加法计算即可
- 做法1:【静态补0】先把两个字符串长度补齐,短的在前面补0,补齐后方便统一处理
class Solution:
def addStrings(self, num1: str, num2: str) -> str:
str1, str2 = num1, num2
l1, l2 = len(str1), len(str2)
# 补齐长度,不足就补0
if l1 < l2:
str1 = '0' * (l2-l1) + str1
elif l1 > l2:
str2 = '0' * (l1-l2) + str2
res = ''
carrier = 0
for index in range(len(str1)-1, -1, -1):
temp = int(str1[index]) + int(str2[index]) + carrier
mod = temp % 10
carrier = temp // 10
res = str(mod) + res
# 跳出循环之后处理一下carrier
if carrier != 0:
res = str(carrier) + res
return res
- 做法2:【地位等价,动态补0 -> 优质模板】使用两个指针指向num1和num2的末端。这时,指针和carrier地位平等,只要任意一处有值,就要加入temp_res;没有值则不加(等同于+0)
这个写法比较优美,思维更加灵活,可泛化
class Solution:
def addStrings(self, num1: str, num2: str) -> str:
i, j = len(num1) - 1, len(num2) - 1
carrier = 0
res = ''
while i >= 0 or j >= 0 or carrier != 0:
temp_res = 0
if i >= 0:
temp_res += int(num1[i])
if j >= 0:
temp_res += int(num2[j])
temp_res += carrier
mod = temp_res % 10
carrier = temp_res // 10
res = str(mod) + res
i -= 1
j -= 1
return res
由本写法泛化的 leetcode面试题 02.05. 链表求和
链表倒序存放,返回求和后的倒序链表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
ans_pre = ListNode('')
poiter = ans_pre
carrier = 0
while l1 or l2 or carrier != 0:
temp_val = 0
if l1:
temp_val += l1.val
l1 = l1.next
if l2:
temp_val += l2.val
l2 = l2.next
temp_val += carrier
mod = temp_val % 10
carrier = temp_val // 10
poiter.next = ListNode(mod)
poiter = poiter.next
poiter.next = None
return ans_pre.next
2.字符串乘法
竖式乘法里面,先拿乘数的每一位,乘以被乘数,然后把所有乘积位移后相加。也就是说,相比字符串加法,前面多了一个乘法过程
class Solution:
def multiply(self, num1: str, num2: str) -> str:
# 【优化点】用字典来保存乘数num2的每一个digit乘以被乘数num1的结果,可以在一定程度上避免重复计算
temp_res_dict = dict()
res = ''
cnt = 0
for i in num2[::-1]:
if i in temp_res_dict:
temp_res = temp_res_dict[i]
else:
# 乘数的一个digit乘以整个被乘数
carrier = 0
temp_res = ''
for j in num1[::-1]:
temp = int(i) * int(j) + carrier
mod = temp % 10
carrier = temp // 10
temp_res = str(mod) + temp_res
if carrier != 0:
temp_res = str(carrier) + temp_res
temp_res_dict[i] = temp_res
res = self.add(res, temp_res+'0'*cnt)
cnt += 1
if res and res[0] == '0':
return '0'
return res
# 字符串相加
def add(self, str1, str2) -> str:
l1, l2 = len(str1), len(str2)
# 补齐长度,不足就补0
if l1 < l2:
str1 = '0' * (l2-l1) + str1
elif l1 > l2:
str2 = '0' * (l1-l2) + str2
res = ''
carrier = 0
for index in range(len(str1)-1, -1, -1):
temp = int(str1[index]) + int(str2[index]) + carrier
mod = temp % 10
carrier = temp // 10
res = str(mod) + res
if carrier != 0:
res = str(carrier) + res
return res
小结
字符串相加、链表相加,本质上都要按位模拟竖式运算,涉及到对应位数求和+进位
做法2将digit和carrier一视同仁,地位平等,存在任意一个就处理。这样就将复杂的长度判断、进位判断等条件判断收敛到一处,即只判断是否存在digit or carrier,大大简化了问题,提升代码可写可读性