前言
本专栏汇总刷题过程中一些相似度极高的数道题的思考逻辑,欢迎大家指出宝贵意见!
提示:以下是本篇文章正文内容,下面案例可供参考
一、题目大意
基本主体是两个非负整数(字符串或数组形式),求二者的和。
LC题目标号较多,由低到高排序为:
- 剑指offer 65 不用加减乘除做加法
- 剑指offer II 002 二进制加法
- 2 两数相加
- 43 字符串相乘
- 66 加一
- 67 二进制求和
- 415 字符串相加
- 989 数组形式的整数加法
下面对这几道题分别进行归类介绍。
二、解题思路
1.不用加减乘除做加法
- 剑指offer 65 不用加减乘除做加法
使用逻辑运算符 异或(^)、与(&)进行求解。
注意:a、b可能为0或负数,要求结果不会溢出32位整数
具体步骤看代码及其注释,代码源于LC的K神,其讲解非常详细可以点击链接学习:
//代码粘贴处
class Solution:
def add(self, a: int, b: int) -> int:
x = 0xffffffff
# python特色 用于获取补码
a,b = a&x,b&x
while b != 0:
# 非进位位 (a^b)
# 进位位 (a&b) << 1 & x
a,b = (a^b),(a&b) << 1 & x
return a if a <= 0x7fffffff else ~(a^x)
2.二进制加法
剑指offer II 002 二进制加法
2 两数相加
67 二进制求和
415 字符串相加
989 数组形式的整数加法
上述四道题,都可以参考一个典型的模板进行解题,代码参考了LC的老汤大佬的,可以点击链接加深学习!
下面将对每道题进行详细阐述
- 题意:两个字符串格式的二进制数字相加。注:每个字符串仅有‘0’和‘1’组成;字符串a、b的长度位于闭区间[1,10^4];字符串若不为‘0’,则都不含前导零,即不存在‘01’的情况。
- 解题思路:依次取出各字符串的每一位,进行进位和非进位运算。
- 代码:
class Solution:
def addBinary(self, a: str, b: str) -> str:
ans = ""
n1,n2,carry = len(a)-1,len(b)-1,0
while n1>=0 or n2>=0:
# 依次取出各位
x = ord(a[n1]) - ord('0') if n1>=0 else 0
y = ord(b[n2]) - ord('0') if n2>=0 else 0
sum = x+y+carry
# 保存非进位位
ans += str(sum%2)
# 保存进位位
carry = sum//2
n1,n2 = n1-1,n2-1
if carry != 0: ans += str(carry)
return ans[::-1]
- 题意:两个非空链表,表示两个非负整数,逆序存储,且每个节点存储一位数字。注:每个链表长度在[1,100]内;节点值属于[0,9];不存在前导零。简单用一个列表表示一下:
- 解题思路:与上题一样的思路,不过注意链表的特有数据结构哦!
- 代码:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
# 定义 头与当前指针
head = cur = ListNode(-1)
carry = val = 0
while carry or l1 or l2:
val = carry
if l1:
# 记住交换是同时间完成的,即 val记录的是当前l1.val
l1,val = l1.next,l1.val+val
if l2:
l2,val = l2.next,l2.val+val
carry,val = divmod(val,10)
cur.next = cur = ListNode(val)
return head.next
- 题意:两个二进制字符串返回它们的和。
- 解题思路:与剑指offer II 002 二进制加法一个解题模板。
- 代码:
class Solution:
def addBinary(self, a: str, b: str) -> str:
ans = ""
num1,num2 = a,b
i,j,carry = len(num1)-1,len(num2)-1,0
while i>=0 or j>=0:
n1 = int(num1[i]) if i>=0 else 0
n2 = int(num2[j]) if j>=0 else 0
tmp = n1+n2+carry
carry = tmp // 2
ans = str(tmp%2)+ans
i,j = i-1,j-1
return "1"+ans if carry else ans
- 题意:与67 二进制求和一致。
- 代码:
class Solution:
def addStrings(self, num1: str, num2: str) -> str:
res = ""
i,j,carry = len(num1)-1,len(num2)-1,0
while i>=0 or j>=0:
n1 = int(num1[i]) if i>=0 else 0
n2 = int(num2[j]) if j>=0 else 0
tmp = n1+n2+carry
carry = tmp //10
res = str(tmp%10)+res
i,j = i-1,j-1
return "1"+res if carry else res
- 题意:与415 字符串相加非常相似,不过换成了十进制。有稍微不同的地方强调一下:返回整数且输入k也是一个整数。
- 代码:
class Solution:
def addToArrayForm(self, num: List[int], k: int) -> List[int]:
ans = []
i,carry = len(num)-1,0
while i>=0 or k!=0:
n1 = num[i] if i >= 0 else 0
n2 = k % 10 if k != 0 else 0
tmp = n1+n2+carry
carry = tmp //10
ans.append(tmp % 10)
i,k = i-1,k//10
if carry != 0: ans.append(carry)
return ans[::-1]
3.样本扩展
43 字符串相乘
66 加一
先简单归纳一下,不用加减乘除的加法从较为底层上去理解加法,无非两部分一部分是进位位,另一个则是非进位位,后续的四道题则除了考虑加法的两部分运算外,更需要根据实际情况获取相加的各位,这样说来有些模糊,做一下上面两道题就更加清晰了。
- 题意:两个字符串形式的非负整数相乘,返回字符串形式的乘积。注:不能使用任何内置的BigInteger库或直接将输入转化为整数;字符串长度位于[1,200];字符串仅由数字组成;都不包含签到零。
- 解题思路:按照数字位拆了两个字符串,令其分别相乘再相加,
- 代码:
class Solution:
def multiply(self, num1: str, num2: str) -> str:
if num1 == '0' or num2 == '0': return '0'
l1,l2 = [],[]
n1,n2 = len(num1)-1,len(num2)-1
for i in num1:
l1.append(int(i)*10**n1)
n1 -= 1
for j in num2:
l2.append(int(j)*10**n2)
n2 -= 1
ans = 0
for i in l1:
for j in l2:
ans += i*j
return str(ans)
- 题意:给一个列表形式的非负整数加一。注:列表的每一位均为[0,9]的整数;不存在前导零;列表长度属于[1,100]。
- 解题思路:依次取出列表内元素,还原非负整数,加一后再进行拆解。
- 代码:
class Solution:
def plusOne(self, digits: List[int]) -> List[int]:
ans,num,n = [],0,len(digits)-1
for i in digits:
num += i * 10**(n)
n -= 1
num += 1
while num:
ans.append(num%10)
num //= 10
return ans[::-1]
三、总结
上述8道题属于典型的运算题,除了第一道题不容易想起来外,其他题均可以按照第二道题的模板思路进行解题:那便是依次取出进行加法操作的元素,分成进位位与非进位位两部分,最后进行对应输出类型的存储。