文章目录
- 第一章:Leetcode 每日很多题
-
- 1、Leetcode-1047 删除字符串中的所有相邻重复项
- 2、剑指 Offer 53 - I. 在排序数组中查找数字 I
- 3、Leetcode704:二分查找
- 4、 Leetcode 227:基本计算器II
- 5、leetcode 224:基本计算器(带括号的计算)
- 6、Leetcode 15:三数之和:排序+双指针
- 7、剑指 offer 38.字符串的排列
- 8、Leetcode409:最长回文串
- 9、Leetcode 331:验证二叉树的前序序列化
- 10、Leetcode 705:设计哈希集合
- 11、Leetcode 13:罗马数字转整数:
- 12、Leetcode 88:合并两个有序数组
- 13、Leetcode 706:设计哈希映射
- 14、Leetcode 54 螺旋矩阵:
- 15、 Leetcode 14 最长公共前缀
- 16、Leetcode 20:有效的括号
- 17、Leetcode 21:合并两个有序的链表
- 18、Leetcode 139:单词拆分问题
- 19、剑指Offer 29:顺时针打印矩阵
- 20、LCP 11: 期望个数统计
- 21、Leetcode 59:螺旋矩阵II
- 22、Leetcode 101 : 对称二叉树
- 23、Leetcode 115:不同的子序列
- 24、Leetcode 1603 :设计停车系统
- 25、Leetcode 290:单词规律
- 26、Leetcode 6:Z字形变换
- 27、Leetcode 914:卡牌分组
- 28、面试题 01.08 零矩阵:
- 29、Leetcode 150:逆波兰表达式求值
- 30、Leetcode 232:用栈实现队列
- 31、Leetcode 503:下一个更大元素II
- 32、Leetcode 131:分割回文串
- 33、Leetcode 92:反转链表II
- 第二章 二叉树/N叉树
- 第三章:哈希表
- 第四章 递归
-
- 1、 Leetcode-70: 爬楼梯问题
- 2、Leetcode-22:括号生成问题
- 3、Leetcode 98:验证二叉搜索树
- 4、Leetcode226:翻转二叉树
- 5、Leetcode104:二叉树的最大深度
- 6、Leetcode111:二叉树的最小深度
- 7、Leetcode509:斐波那契数列
- 8、Leetcode 297:二叉树的序列化和反序列化
- 9、Leetcode236:二叉树的公共祖先
- 10、Leetcode 105:从前序与中序遍历序列构造二叉树
- 11、 Leetcode 77: permutation
- 12、Leetcode 46:全排列
- 13、Leetcode 47:全排列II
- 第五章 动态规划
-
- 1、Leetcode 62:不同路径
- 2、Leetcode 63:不同路径II
- 3、Leetcode 1143:最长公共子序列
- 4、Leetcode 70:爬楼梯
- 5、Leetcode 120:三角形的最小路径和
- 6、Leetcode 55: 最大子序和
- 7、Leetcode 152:乘积最大子树和
- 8、Leetcode 332:零钱兑换问题
- 9、Leetcode 198:打家劫舍
- 10、Leetcode 121:买卖股票的最佳时机
- 11、Leetcode 122:买入股票的最佳时机II
- 12、Leetcode 123:买卖股票的最佳时机III
- 13、Leetcode 309:最佳买卖股票时机含冷冻期
- 14、Leetcode 188:买卖股票的最佳时机IV
- 15、Leetcode 714:买卖股票的最佳时机含手续费
- 16、Leetcode 32:最长有效括号
- 17、Leetcode 64:最小路径和
- 18、Leetcode 72 :编辑距离
- 19、Leetcode 91:解码方法
- 20、Leetcode 221:最大正方形
- 21、Leetcode 403:青蛙过河
- 22、Leetcode 410:分割数组的最大值
- 23、Leetcode 552:学生出勤记录II
- 24、Leetcode 647:回文子串
- 25、Leetcode 76:最小覆盖子串
- 26、Leetcode 312:戳气球
- 27、Leetcode 213:打家劫舍ii
- 28、Leetcode 300:最长递增子序列
- 29、Leetcode 53:最大子序列和
- 30、Leetcode 72:编辑距离计算
- 31、Leetcode 332:零钱兑换
- 32、Leetcode 494:目标和
- 总结
- 第六章 分治、回溯
- 第七章 深度优先搜索和广度优先搜索
- 第八章 :贪心搜索
- 第九章 二分查找
- 第十章 字典树
- 第十一章 并查集
- 第十二章 高级搜索
- 第十三章 红黑树和AVL树
- 第十四章 排序算法
- 第十五章 字符串相关问题
-
- 1、Leetcode 709 转换成小写字母
- 2、Leetcode 58:最后一个单词的长度
- 3、Leetcode 771:宝石与石头
- 4、剑指offer 50:第一个只出现一次的字符
- 5、Leetcode 8:字符串转换整数
- 6、Leetcode 14:最长公共前缀
- 7、Leetcode 344:反转字符串
- 8、Leetcode 541:反转字符串ii
- 9、Leetcode 151:反转字符串里的单词
- 10、Leetcode 557:反转字符串中的单词III
- 11、Leetcode 917:仅仅反转字母
- 12、Leetcode 242:有效的字母异位词重写
- 13、Leetcode 49:字母异位词分组:
- 14、Leetcode 438:找到字符串中的所有字母异位词
- 15、Leetcode 1143:最长公共子序列重写
- 16、Leetcode 125:验证回文串
- 17、Leetcode 680:验证回文字符串ii
- 18、Leetcode 5:最长回文子串
- 19、Leetcode 72:编辑距离重写
- 20、Leetcode 10:正则表达式匹配
- 21、Leetcode 44:通配符匹配
- 22、Leetcode 115:不同的子序列重写
- 23、Leetcode 387:字符串中的第一个唯一字符
- 24、Leetcode 8:字符串转换整数重写
- 25、Leetcode 541:反转字符串II重写
- 26、Leetcode 151:翻转字符串里的单词重写
- 27、Leetcode 537:反转字符串中的单词iii重写
- 28、Leetcode 917:仅反转字母重写
- 29、Leetcode 438:找到字符串中所有字母异位词重写
- 30、Leetcode 5:最长回文串重写
- 31、Leetcode 205:同构字符串
- 32、Leetcode 680:验证回文字符串II重写
- 33、Leetcode 44:通配符匹配重写
- 34、Leetcode 32:最长有效括号重写
- 35、Leetcode 115:不同的子序列重写
- 第十六章 高级动态规划
- 第十七章 布隆过滤器&LRU cache
- 第十八章 位运算
第一章:Leetcode 每日很多题
1、Leetcode-1047 删除字符串中的所有相邻重复项
题目描述:
题目思路:
使用stack的思路,先把字符串的第一个字母压栈,然后判断下一个待压栈的字母是否与stack[-1]的字母相同,如果相同,该字母不进入stack中,且stack.pop()将重复的字母剔除。如此遍历一遍字符串,最后返回stack中的元素即为消除重复字后的字符串。
举例:"abbaca"
- 建立栈
- 把a压栈
- b与a不相同,压栈
- 第二个b和stack栈口元素相同,不要第二个b且把栈扣的b pop掉。
- 第四个元素:a,此时stack中还有一个元素a,相同,不要第四个元素且把stack中的a pop掉
- 压c,压a
- 返回ca即为结果
代码:
def main(S):
stack=[]
for i in S:
if stack and stack[-1]==i:
stack.pop()
else:
stack.append(i)
return "".join(stack)
2、剑指 Offer 53 - I. 在排序数组中查找数字 I
代码实现
class Solution:
def search(self, nums: List[int], target: int) -> int:
dic1=collections.defaultdict(int)
for i in nums:
dic1[i]+=1
return dic1[target] if dic1[target] else 0
3、Leetcode704:二分查找
题目描述
代码实现
class Solution:
def search(self, nums: List[int], target: int) -> int:
left=0
right=len(nums)-1
while left<=right:
mid=(left+right)//2
if nums[mid]>target:
right=mid-1
elif nums[mid]<target:
left=mid+1
else:
return mid
return -1
4、 Leetcode 227:基本计算器II
题目描述:
解题思路:
首先对于计算器来说有加减乘除四种符号,对于加减的符号,运算主要看加减符号后面的两个数字。对于乘除符号,运算主要看乘除符号前后的数字。解题思路是维护一个栈,遍历输入字符串,当遇到的都是数字那么把它们做累加定义为变量num,当遍历到不是数字时,空格的话忽略。如果是计算符号,在当前时刻查看上一个符号,会有四种情况:
- “+”:只需把num的数字压栈即可
- “-”:只需把num的相反数压栈即可
- “*”:需要从栈中取出上一次压栈的数字并与当前num做乘法压栈。
- “/”:需要把栈中上一次压栈的数字并与当前num做除法取整即可。
对于出现计算符号的每个时刻计算的都是它前面保留的num和上一次符号的计算。所以当前时刻计算压栈后,prev_flag定义为当前符号,在下一次出现计算符号开始计算,num作为计数变量也要清零。
代码
class Solution:
def calculate(self, s: str) -> int:
s+="$"
stack=[]
pre_flag="+"
num=0
for i in s:
if i.isdigit():
num=num*10+int(i)
elif i==" ":
continue
else:
if pre_flag=="+":
stack.append(num)
elif pre_flag=="-":
stack.append(-(num))
elif pre_flag=="*":
stack.append(stack.pop()*num)
elif pre_flag=="/":
stack.append(int(stack.pop()/num))
pre_flag=i
num=0
return sum(stack)
5、leetcode 224:基本计算器(带括号的计算)
解题思路:
与第九题大致相同,但加入一个递归去计算每次括号中的数字,并且返回,如此递归下去。
class Solution:
def calculate(self, s: str) -> int:
def dfs(s,start):
stack=[]
prev_flag="+"
i=start
num=0
while i <len(s):
if s[i]==" ":
i+=1
continue
elif s[i].isdigit():
num=num*10+int(s[i])
elif s[i]=="(":
i,num=dfs(s,i+1)
else:
if prev_flag=="+":
stack.append(num)
elif prev_flag=="-":
stack.append(-num)
if s[i]==")":
break
prev_flag=s[i]
num=0
i+=1
return i,sum(stack)
s+="$"
return dfs(s,0)[1]
6、Leetcode 15:三数之和:排序+双指针
解题思路:
首先面对三树之和,先将列表用sort进行排序,然后第一层遍历每一个元素,对于每一次每一个位置的元素,都设定左右指针,右指针指list最后,左指针为当前元素的下一个。即:
- left=i+1
- right=len(list)-1
接下来就是一个判别式,具体为三种情况: - 如果左右指针对应元素小于target-list[i],说明最小的不够大,left指针加1
- 如果左右指针对应元素大于target-list[i],说明最大的不够小,right指针减1
- 如果左右指针对应元素相加正好等于target-list[i],满足题意,把三个数存储在列表排序经过tuple后添加到res集合中。左右指针分别加1减1继续查看。
- 最后只要把res列表化就可以了
两个问题:
- 第一个问题是为了达到去重的效果我是把列表sorted后tuple化添加到集合中的,然后再把集合list,其实里面的还是tuple,但是在leetcode中输出的还是list of list的形式。不太明白这段怎么处理。
- 常见的三数之和也可以使用哈希表加两层for循环查找,但在之前的题目中,我是通过字典存储nums中每个元素是否出现,然后两层for 循环查找是否target-j-k是否在字典中。但该题中列表元素中有重复的,那么使用哈希表就还要存储它在nums中的index,这点没有想到办法处理。只能使用排序+双指针好理解一些。后续的处理是建立一个新列表,遍历集合中的元组列表化插入新的列表。这样就不需要判断和上一次枚举的不同的这个条件了。
代码
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
res=set()
for i in range(len(nums)):
j=i+1
k=len(nums)-1
while j <k:
if nums[j]+nums[k]<-nums[i]:
j+=1
elif nums[j]+nums[k]>-nums[i]:
k-=1
else:
res.add(tuple(sorted([nums[j],nums[k],nums[i]])))
k-=1
j+=1
list1=[]
for j in res:
list1.append(list(j))
return list1
7、剑指 offer 38.字符串的排列
问题描述
解题思路
最直接的办法就是对于一个给定字符串,对于第一个位置可以是任何字符串中的任何一个字母,分类讨论,固定好第一个字母,从剩下的字母中选择去固定下一个字母位置,如此递归,终止条件即位len-1的位置也固定好了以后,返回每一种情况。在其中要注意的是,如果列表中出现重复的字母的话,使用set()去重后,不需要让重复的再进行固定了。
代码
class Solution:
def permutation(self, s: str) -> List[str]:
c,res=list(s),[]
def dfs(x):
#终止条件:
if x==len(s)-1:
res.append("".join(c))
return
dic=set()
#循环字符串的每一个位置
for i in range(x,len(c)):
if c[i] in dic:#重复的不需要固定
continue
dic.add(c[i])
c[i],c[x]=c[x],c[i]
dfs(x+1)#对下一位进行递归
c[i],c[x]=c[x],c[i]#调换回来
dfs(0)
return res
8、Leetcode409:最长回文串
题目描述
代码
class Solution:
def longestPalindrome(self, s: str) -> int:
n=len(s)
li=[s.count(i)%2 for i in set(s)]
return n - max(0,sum(li)-1)
9、Leetcode 331:验证二叉树的前序序列化
题目描述
解题思路:
如果对于一个节点,它的两个子节点都是"#",那么可以将这一组节点变为#。
例如
9,#,# ——>#,再去和他的上一层进行比较。遍历一遍前序遍历的列表,如果到最后只剩下["#"]表示序列化正常。
代码实现:
class Solution:
def isValidSerialization(self, preorder: str) -> bool:
stack=[]
for i in preorder.split(","):
stack.append(i)
while len(stack)>=3 and stack[-1]==stack[-2]=="#" and stack[-3]!="#":
stack.pop(),stack.pop(),stack.pop()
stack.append("#")
return len(stack)==1 and stack.pop()=="#"
10、Leetcode 705:设计哈希集合
题目描述
解题思路
对于输入的key使用key%1009作为哈希函数存储,无论是add,remove还是contain都通过查看self.table[hashkey]中是否有当前key来决定操作。self.table是一个列表存储了哈希的键位和值。
代码
class MyHashSet:
def __init__(self):
"""
Initialize your data structure here.
"""
self.buckets=1009
self.table=[[] for i in range(self.buckets)]
def hash(self,key):
#将输入的key进入哈希映射
return key%self.buckets
def add(self, key: int) -> None:
hashkey=self.hash(key)
if key in self.table[hashkey]:
return
self.table[hashkey].append(key)
def remove(self, key: int) -> None:
hashkey=self.hash(key)
if key not in self.table[hashkey]:
return
self.table[hashkey].remove(key)
def contains(self, key: int) -> bool:
"""
Returns true if this set contains the specified element
"""
hashkey=self.hash(key)
if key in self.table[hashkey]:
return True
else:
return False
11、Leetcode 13:罗马数字转整数:
题目描述
解题思路
- 定义一个字典存储每个罗马数字对应的int值
- 遍历str,如果当前的这个罗马数字对应的int值是小于下一个的,那么就要在输出值减去当前值
- 否则,就加上当前罗马数字对应的十进制数字。
代码
class Solution:
def romanToInt(self, s: str) -> int:
dic={
"I":1,"V":5,"X":10,"L":50,"C":100,"D":500,"M":1000}
ans=0
for i in range(len(s)):
if i<len(s)-1 and dic[s[i]]<dic[s[i+1]]:
ans-=dic[s[i]]
else:
ans+=dic[s[i]]
return ans
12、Leetcode 88:合并两个有序数组
题目描述
解题思路
定义两个指针,分别遍历两个nums。终止点是指针到达m和n为止。
这里边要注意的是要对nums1进行浅拷贝。
因为有可能p和q一个遍历完了,一个还没有遍历完,所以while循环后要把剩下的使用extend补齐。
代码
class Solution:
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
"""
Do not return anything, modify nums1 in-place instead.
"""
nums1_copy=nums1[:m]
nums1[:]=[]
p=0
q=0
while p < m and q<n:
if nums1_copy[p]<=nums2[q]:
nums1.append(nums1_copy[p])
p+=1
else:
nums1.append(nums2[q])
q+=1
nums1.extend(nums1_copy[p:])
nums1.extend(nums2[q:])
13、Leetcode 706:设计哈希映射
此题比较简单,就直接放代码了
class MyHashMap:
def __init__(self):
"""
Initialize your data structure here.
"""
self.map=[-1]*1000001
def put(self, key: int, value: int) -> None:
"""
value will always be non-negative.
"""
self.map[key]=value
def get(self, key: int) -> int:
"""
Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key
"""
return self.map[key]
def remove(self, key: int) -> None:
"""
Removes the mapping of the specified value key if this map contains a mapping for the key
"""
self.map[key]=-1
14、Leetcode 54 螺旋矩阵:
题目描述
解题思路
对于顺时针遍历螺旋矩阵,最难的点在于何时更改方向,从例子中可以看到,更改方向的点都是走到了行和列的边缘,或者遇到已经走过的点。那么对于本题,需要创建的除了一个存储所有螺旋便利的列表,还需要一个列表存储下一个点的行列信息是否已经走过的状态列表。遍历行和列所有的点,只要加入一次方向后,再该方向上不是边界外的点且没有遍历过,该点就可以加入res列表。除此之外,direction的列表的方向应该按顺时针书写。
代码
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
#统计行和列的数量
row=len(matrix)
col=len(matrix[0])
#所有的元素个数
total=row*col
#建立一个存储是否访问过的矩阵
visited=[[False ] * col for i in range(row)]
#建立一个存储路径的列表
order=[0]*total
#建立顺时针的方向矩阵
direction=[[0,1],[1,0],[0,-1],[-1,0]]
#初始化位置和方向索引
r,c=0,0
direction_idx=0
#开始遍历
for k in range(total):
#向order中添加元素信息
order[k]=matrix[r][c]
#在vistied 中存储路径
visited[r][c]=True
#计算下一个位置的坐标点
next_r=r+direction[direction_idx][0]
next_c=c+direction[direction_idx][1]
#判断这个点是否满足条件
if not (0<=next_r<row and 0<=next_c<col and not visited[next_r][next_c]):
#顺时针更新方向,只需要更新一次方向就可以保证一定可以继续走
direction_idx=(direction_idx+1)%4
#更新r和c的坐标
r+=direction[direction_idx][0]
c+=direction[direction_idx][1]
return order
15、 Leetcode 14 最长公共前缀
题目描述
解题思路
Approach 1:纵向查找
纵向查找,只需要以第一个单词的长度为基准,对比其他单词在每一位上是否相同,如果出现了不同或已经到达了任何一个词的长度,只需要返回前面的i-1个单词即可。
Approach 2: 分治
加入这个strs有四个单词,那么把它分成两份,再对其中每一份进行两两之间的比较,返回两两之间的最长公共前缀,再进行回溯,因为最长公共前缀是所有单词的公共前缀。终止条件是左边界等于右边界。
代码
#纵向搜索
class Solution:
def longestCommonPrefix(self, strs: List[str]) -> str:
if not strs:
return ""
length=len(strs[0])
count=len(strs)
for i in range(length):
if any(i==len(strs[j]) or strs[j][i]!=strs[0][i] for j in range(1,count)):
return strs[0][:i]
#如果都相同
return strs[0][:length]
class Solution:
def longestCommonPrefix(self, strs: List[str]) -> str:
#分治的思想
def dfs(start,end):
#终止条件:
if start == end:
return strs[start]
#将strs里面的字母分开
mid=(start+end)//2
#递归左右两边
left=dfs(start,mid)
right=dfs(mid+1,end)
#对比两个返回的长度,取小的那个
min_length=min(len(left),len(right))
#遍历较短的单词
for j in range(min_length):
#一旦他们出现了不相等的位置
if left[j]!=right[j]:
return left[:j]
#如果都相同,return较短的
return left[:min_length]
return "" if not strs else dfs(0,len(strs)-1)
16、Leetcode 20:有效的括号
题目描述
解题思路
采用栈的思想,遍历字符串中的每一个括号,分成四类讨论:
- 如果是")“且上一个也是”(",那么把上一个出栈
- 如果是”]“且栈的上一个是"[",那么把上一个出栈
- 如果是"}“且栈的最后一个是”{",那么把栈的最后一个出栈。
- 如果不满足上述四个,将当前括号类型压栈。
如果最后stack的长度为0说明符合标准,返回True,否则返回False。
代码
class Solution:
def isValid(self, s: str) -> bool:
stack=[]
n=len(s)
for i in s:
if stack and i=="]" and stack[-1]=="[":
stack.pop()
elif stack and i==")" and stack[-1]=="(":
stack.pop()
elif stack and i=="}" and stack[-1]=="{":
stack.pop()
else:
stack.append(i)
return True if len(stack)==0 else False
17、Leetcode 21:合并两个有序的链表
题目描述
递归方法
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
if l1 is None:
return l2
elif l2 is None:
return l1
elif l1.val > l2.val:
l2.next=self.mergeTwoLists(l1,l2.next)
return l2
else:
l1.next=self.mergeTwoLists(l1.next,l2)
return l1
迭代方法
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
#迭代的方法
#建立一个节点
head=ListNode(-1)
#定义指针
pre=head
while l1 and l2:
if l1.val>l2.val:
pre.next=l2
l2=l2.next
else:
pre.next=l1
l1=l1.next
#比较完要移动一次指针
pre=pre.next
#将剩下的没有添加完的添加进head
pre.next=l1 if l1 is not None else l2
return head.next
18、Leetcode 139:单词拆分问题
题目描述
解题思路
本题使用动态规划解决,建立一个dp列表长度为n+1,每个位置储存的状态为false,dp[i]表示从str[:i]能否满足题意,遍历str的长度,遍历每个i前面的所有字母,只要s[j-1:i]存在在字典,那么dp[i]和dp[j-1]的状态是一样的。
代码
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
#建立一个DP列表
n=len(s)
dp=[False]*(n+1)
#初始化
dp[0]=True
#遍历
for i in range(1,n+1):
for j in range(i,-1,-1):
if s[j-1:i] in wordDict:
dp[i]|=dp[j-1]
return dp[n]
19、剑指Offer 29:顺时针打印矩阵
该题和螺旋矩阵相同,直接上代码
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
#计算行的长度
row=len(matrix)
if row==0:
return []
#计算列的长度
col=len(matrix[0])
#计算有多少个数字
total=col*row
#定义一个存储访问的矩阵
visted=[[False]*col for i in range(row)]
#定义一个最后输出的矩阵
res=[0]*total
#定义方向的列表
direction=[(0,1),(1,0),(0,-1),(-1,0)]
#定义col和row的起始位置
r,c=0,0
direction_id=0
#开始遍历
for i in range(total):
res[i]=matrix[r][c]
visted[r][c]=True
#定义direction id
new_r=r+direction[direction_id][0]
new_c=c+direction[direction_id][1]
#判断这个点是否满足条件
if not (0<=new_r<row and 0<=new_c<col and not visted[new_r][new_c]):
direction_id=(direction_id+1)%4
r+=direction[direction_id][0]
c+=direction[direction_id][1]
return res
20、LCP 11: 期望个数统计
class Solution:
def expectNumber(self, scores: List[int]) -> int:
return len(set(scores))
21、Leetcode 59:螺旋矩阵II
题目描述
解题思路
这道题和原本的螺旋矩阵类似,但是不需要维护一个状态的矩阵,只需要判断matrix中下一个位置的值是否为初始值0。
代码
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
#设定行和列的数量
row,col=n,n
#建立一个填入的矩阵
matrix=[[0]*n for _ in range(n)]
#建立方向
direction=[(0,1),(1,0),(0,-1),(-1,0)]
#建立初始坐标和方向索引
r,c,d=0,0,0
#开始添加
for i in range(n*n):
matrix[r][c]=i+1
new_r=r+direction[d][0]
new_c=c+direction[d][1]
#查看下一个坐标位置是否符合规则
if not(0<=new_c<col and 0<=new_r<row and matrix[new_r][new_c]==0):
#方向顺时针转动一次
d=(d+1)%4
#更新坐标
r+=direction[d][0]
c+=direction[d][1]
return matrix
22、Leetcode 101 : 对称二叉树
题目描述
代码实现
Approach 1:递归
使用递归做,就是定义函数不断地去判断每个左节点下的左子节点,和右节点下的右子节点和左节点下的右子节点和右节点下的左子节点是否相同。这里比较麻烦的是终止条件:
- 条件1:如果left和right都为空,为true:not(left or right)
- 条件2:如果left和right 有一个为空,为False:not(left and right)
- 条件3:如果left和right的val不同,为False
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
if not root:
return True
def dfs(left,right):
#left代表左叶节点,left代表右叶节点
#终止条件1:如果left和right为空
if not (left or right):
return True
#终止条件2:如果left和right有一个为空:
if not (left and right):
return False
#终止条件3,left和right不相等
if left.val!=right.val:
return False
#进入递归
return dfs(left.left,right.right) and dfs(left.right,right.left)
return dfs(root.left,root.right)
Approach 2:队列迭代
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
#建立一个队列
queue=collections.deque()
queue.extend([root.left,root.right])
while queue:
#拿出第一对
left=queue.popleft()
right=queue.popleft()
#如果left和right都为空
if not (left or right):
continue
#如果一个为空:
if not (left and right):
return False
if left.val!=right.val:
return False
#将left的左节点,right的右节点添加队列
queue.extend([left.left,right.right])
#将left的右节点,right的左节点添加队列
queue.extend([left.right,right.left])
return True
23、Leetcode 115:不同的子序列
题目描述
解题思路
转移方程的话已经在代码中写到了,解题思路感觉这个大佬写的最清晰,即如果当前对比的位置字符相同,我可以选择进行匹配或者不进行匹配,因为从右往左的顺序进行匹配的话,即使相同前面可能也会有相同的,所以有两种选择。
代码实现
class Solution:
def numDistinct(self, s: str, t: str) -> int:
#统计两个字符串的长度
m,n=len(s),len(t)
#以t为子串,如果t比s长,不符合题意
if m<n:
return 0
#建立储存的状态矩阵
dp=[[0]*(n+1) for _ in range(m+1)]
#初始化,如果n=0,那么它可以使s的任何子串
for i in range(m+1):
dp[i][n]=1
#如果m=0,没有字串
#开始遍历
for i in range(m-1,-1,-1):
for j in range(n-1,-1,-1):
#如果当前字母匹配
if s[i]==t[j]:
#那么有可能是从s+1,j+1转移,也可能是s+1,j转移
dp[i][j]=dp[i+1][j+1]+dp[i+1][j]
else:
#如果不相等,只能考虑s+1,j
dp[i][j]=dp[i+1][j]
return dp[0][0]
24、Leetcode 1603 :设计停车系统
题目描述
解题思路
这题想通过还是很简单的,不做赘述了。
代码实现
class ParkingSystem:
def __init__(self, big: int, medium: int, small: int):
self.big=big
self.medium=medium
self.small=small
def addCar(self, carType: int) -> bool:
if carType==3:
if self.small>=1:
self.small-=1
return True
else:
return False
elif carType==2:
if self.medium>=1:
self.medium-=1
return True
else:
return False
else:
if self.big>=1:
self.big-=1
return True
else:
return False
25、Leetcode 290:单词规律
题目描述
解题思路
- 使用两个哈希表
word2char:存储当前词key对应的字母value
char2word:存储当前字母key对应的单词value - 那么判断其为false的就有两个条件
1、当前词已经出现在word2char中了,但对应的char并不是当前的char
2、当前char已经出现在char2word里了,但对应的word不是当前的word - 使用zip(pattern,word_list)进行打包遍历
代码实现
class Solution:
def wordPattern(self, pattern: str, s: str) -> bool:
word2chr={
}
chr2word={
}
#如果长度不相等,直接返回错
word_list=s.split()
if len(pattern)!=len(word_list):
return False
for char,word in zip(pattern,word_list):
#如果词在词典中出现,但对应的字母和word2chr的不同
#如果字母在字典中出现,但对应的词和chr2word存储的不同
if (word in word2chr and word2chr[word] !=char) or (char in chr2word and chr2word[char]!=word):
return False
word2chr[word]=char
chr2word[char]=word
return True
26、Leetcode 6:Z字形变换
题目描述
解题思路
把这道题想得简单些,加入输入的numsRows有三行,那么添加字符串中的顺序应该是012|1|012|1
也就是说只要定义一个变量去存储方向状态即可
- i==0时,flag为+1
- 达到i==row-1后,flag为-1
代码实现
class Solution:
def convert(self, s: str, numRows: int) -> str:
if numRows < 2: return s
res = ["" for _ in range(numRows)]
i, flag = 0, -1
for c in s:
res[i] += c
if i == 0 or i == numRows - 1: flag = -flag
i += flag
return "".join(res)
作者:jyd
链接:https://leetcode-cn.com/problems/zigzag-conversion/solution/zzi-xing-bian-huan-by-jyd/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
27、Leetcode 914:卡牌分组
题目描述
代码实现+步骤详解
class Solution:
def hasGroupsSizeX(self, deck: List[int]) -> bool:
#统计牌组中每一种牌出现的次数
count_list=collections.Counter(deck)
#统计长度
n=len(deck)
#对X进行遍历
for x in range(2,n+1):
#条件1:x是长度的约数
if n%x==0:
#条件2:x是每个牌出现次数的约数
if all(v%x==0 for v in count_list.values()):
return True
#如果遍历完所有x取值的可能都没达到条件,返回False
return False
28、面试题 01.08 零矩阵:
题目描述
代码实现
第一次遍历,存储matrix位置为0的row和col,第二次遍历将row和
col为0的所有位置都变成0。
class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
row=len(matrix)
col=len(matrix[0])
r,c=[0]*row,[0]*col
for i in range(row):
for j in range(col):
if matrix[i][j]==0:
r[i]=1
c[j]=1
for i in range(row):
for j in range(col):
if r[i]==1 or c[j]==1:
matrix[i][j]=0
29、Leetcode 150:逆波兰表达式求值
题目描述
解题思路
维护一个栈,遍历tokens
- 如果token为数字,压栈
- 当遇到了加减乘除符号,拿出栈的后两个进行计算后,将计算值压栈。
- 返回stack中最后的值。
代码实现
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
stack=[]
for token in tokens:
if token in ["+","-","/","*"]:
b=stack.pop()
c=stack.pop()
if token=="*":
stack.append(b*c)
elif token=="/":
stack.append(int(c/b))
elif token=="+":
stack.append(b+c)
else:
stack.append(c-b)
else:
stack.append(int(token))
return int(stack[-1])
30、Leetcode 232:用栈实现队列
题目描述
解题思路
这种简单的题是真实存在的么…
代码实现
class MyQueue:
def __init__(self):
"""
Initialize your data structure here.
"""
self.queue=[]
def push(self, x: int) -> None:
"""
Push element x to the back of queue.
"""
self.queue.append(x)
def pop(self) -> int:
"""
Removes the element from in front of queue and returns that element.
"""
return self.queue.pop(0)
def peek(self) -> int:
"""
Get the front element.
"""
return self.queue[0]
def empty(self) -> bool:
"""
Returns whether the queue is empty.
"""
return len(self.queue)==0
31、Leetcode 503:下一个更大元素II
题目描述
解题思路
做多了dp感觉这种题还是很简单的。主要说一下三个核心点:
- 1、因为是循环数组,所以遍历n*2-1次,每个位置用i对n取模达到定位
- 2、代码中,res列表存储的是每个位置的下一个最大值,stack中存储的是nums中每个的下标。
- 3、对于当前nums[i]的值来说,遍历stack中其他的下标,如果stack中其他下标对应的值小于了nums[i],那么先要将res对应的位置添加nums[i],说明这些位置的下一个最大值就是nums[i],然后再把nums[i]压栈去寻找nums[i]的下一个最大元素。
代码实现
class Solution:
def nextGreaterElements(self, nums: List[int]) -> List[int]:
n=len(nums)
#维护一个列表储存每个下标对应的下一个最大值
res=[-1]*n
#建立一个栈,存储的是下标
stack=[]
#因为是循环数组,遍历2n次
for i in range(n*2-1):
#只要栈中的元素比当前元素小,就pop
while stack and nums[stack[-1]]<nums[i%n]:
res[stack.pop()]=nums[i%n]
stack.append(i%n)
return res
32、Leetcode 131:分割回文串
题目描述
解题思路
这道题分为递归和dp两个部分
1、dp部分::判断
判断i到j是否为回文串,如果当前i和j的位置相等,且i+1到j-1的位置也是回文串,那么 d p [ i ] [ j ] dp[i][j] dp[i][j]是回文串。
2、递归部分::遍历
对于当前位置的i,遍历i后面的所有元素,判断i,j是否为回文串,如果是,将level中存储这部分的值,因为i,j已经是回文串了,那么要对j+1开始判断是j+1,n是否为回文串,当j到达n时,把这部分的值存储到res中。返回上一层,每返回一层还要讲该层的信息删除pop掉。
代码实现
class Solution:
def partition(self, s: str) -> List[List[str]]:
n=len(s)
#DP部分,表示i-j部分的字符串是否为回文串的判断
dp=[[True]*n for _ in range(n)]
for i in range(n-1,-1,-1):
for j in range(i+1,n):
#i=j是回文串的条件是当前元素对应值相等且i+1:j-1也是回文串
dp[i][j]=dp[i+1][j-1] and s[i]==s[j]
#存储所有结果
res=[]
#递归过程中存储每个结果
level=[]
def dfs(i):
#终止条件:
if i==n:
res.append(level[:])
return
#对于每个i进行分析
for j in range(i,n):
#如果当前是回文串
if dp[i][j]:
level.append(s[i:j+1])
#对于j+1开始判断
dfs(j+1)
#删除前面的可能
level.pop()
dfs(0)
return res
33、Leetcode 92:反转链表II
题目描述
解题思路
- 先将指针定位到反转区域的前一个元素,定义pre,cur,next
- 对于需要反转的区域,每次不算的把pre cur next的位置翻转为pre next cur。pre是固定的
代码实现
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode:
#设置头节点
dummy=ListNode(-1)
dummy.next=head
#前节点
pre=dummy
#定位到left的前一个位置
for i in range(left-1):
pre=pre.next
#定位到left的第一个位置
cur=pre.next
#遍历需要反转的区域
for j in range(right-left):
#找到前一个节点
next=cur.next
#将cur指向前一个的前一个
cur.next=next.next
#将next指向cur
next.next=pre.next
#将pre指向next
pre.next=next
return dummy.next
第二章 二叉树/N叉树
1、Leetcode 94:二叉树的中序遍历
题目描述:
使用递归的思想
使用递归的思想即为对于每个根节点都按照左根右的方式进行遍历,递归的思路即为先对根节点的左子节点进行递归,然后打印或添加,然后再对根节点的右子节点进行递归。如果对于当前递归层的节点来说,它不是root,则返回上一层递归操作。
代码实现:
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
res=[]
def dfs(root):
if not root:
return
dfs(root.left)
res.append(root.val)
dfs(root.right)
dfs(root)
return res
颜色标记法
使用stack的思想,先进后出。定义新的节点为白色,已经遍历过的节点为灰色,如果第一次看到的节点是白色,就要把当前节点的按照右,中,左的顺序依次入栈。同时还要不算的出栈,出栈的顺序即为左、中、右。对于每一次节点的进栈,它本身的节点已经被看过了,将其变成灰色标记存入栈中,即下次出栈出到这个节点时,它本身就是灰色,不需要处理,直接出栈即可。而它的左子节点和右子节点还没有被看过,需要先进栈再出栈才算被看过,所以标记为白色。
代码实现:
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
res=[]
white,gray=0,1
stack=[(white,root)]
while stack:
color,node=stack.pop()
if node is None:
continue
if color==white:
stack.append((white,node.right))
stack.append((gray,node))
stack.append((white,node.left))
else:
res.append(node.val)
return res
维护一个栈迭代的思想
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
res=[]
stack=[root]
while stack:
while root.left:
stack.append(root.left)
root=root.left
cur=stack.pop()
res.append(cur.val)
if cur.right:
stack.append(cur.right)
root=cur.right
return res
2、Leetcode 144:二叉树的前序遍历
递归的思路
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
res=[]
def dfs(root):
if root:
res.append(root.val)
dfs(root.left)
dfs(root.right)
dfs(root)
return res
颜色标记法
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
res=[]
white,gray=0,1
stack=[(white,root)]
while stack:
color,node=stack.pop()
if node is None:
continue
if color==white:
stack.append((white,node.right))
stack.append((white,node.left))
stack.append((gray,node))
else:
res.append(node.val)
return res
迭代的方法维护一个栈
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
res=[]
stack=[]
node=root
while stack or node:
while node:
res.append(node.val)
stack.append(node)
node=node.left
node=stack.pop()
node=node.right
return res
3、Leetcode 145:二叉树的后序遍历
使用递归的思想
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
res=[]
def dfs(root):
if root:
dfs(root.left)
dfs(root.right)
res.append(root.val)
dfs(root)
return res
使用颜色标记法
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
white, gray=0,1
stack=[(white,root)]
res=[]
while stack:
color , node =stack.pop()
if not node:
continue
if color==white:
stack.append((gray,node))
stack.append((white,node.right))
stack.append((white,node.left))
else:
res.append(node.val)
return res
使用迭代的思想
实现左右根的思路感觉很难,所以将前序遍历中的根左右,变为根右左再逆序就得到了左右根。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
res,stack=[],[]
node=root
while node or stack:
while node:
res.append(node.val)
stack.append(node)
node=node.right
cur=stack.pop()
node=cur.left
return res[::-1]
4、N叉树的后续遍历
使用递归的思想
对于N叉树的后续遍历其实与二叉树差不多,只不过对于每个节点,需