跟随代码随想录https://programmercarl.com/的刷题记录
1.15
栈
class Solution(object):
def evalRPN(self, tokens):
"""
:type tokens: List[str]
:rtype: int
"""
arr = []
while tokens:
if len(tokens)!=0:
arr.append(tokens.pop(0))
if arr[len(arr)-1] =='/' or arr[len(arr)-1]=='*' or arr[len(arr)-1]=='+' or arr[len(arr)-1]=='-':
key=str(arr[len(arr)-3])+str(arr[len(arr)-1])+str(arr[len(arr)-2]) #匹配到运算符则将运算符和前面两个合成为一个字符串
arr.pop()
arr.pop()
arr.pop() #并删除最后三个
arr.append(int(eval(key))) #算出结果后添加进数组
return int(arr[0])
class Solution:
def isValid(self, s: str):
sta =[]
for i in s:
if i== '(':
sta.append(')')
elif i == '[':
sta.append(']')
elif i == '{':
sta.append('}')
elif len(sta) == 0 or sta[-1] != i: # 如果sta空了说明右括号有多 或者不匹配,直接返回false
return False
else:
sta.pop() #括号匹配成功,弹出最后一位
return True if not sta else False #循环结束如果sta内还有内容,说明左括号有多,则返回false
数组,模拟过程
class Solution:
def generateMatrix(self, n):
arr=[[0]*n]*n
for i in range(len(arr)): #创建n*n的矩阵
arr[i]=arr[i]*1
num=1
left, right, up, down = 0, n - 1, 0, n - 1
while left<right and up <down:
for x in range(left,right):
arr[up][x]=num
num+=1
for y in range(up,down):
arr[y][right]=num
num+=1
for x in range(right,left,-1):
arr[down][x]=num
num+=1
for y in range(down,up,-1):
arr[y][left]=num
num+=1
left+=1 #开始缩小范围,直到left>right 和 up >down 退出循环
up+=1
right-=1
down-=1
if n%2==1: #如果n为奇数,在中间补上数字
arr[n//2][n//2]=num
return arr
1.16
二叉树
三种深度遍历
# 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: Optional[TreeNode]) -> List[int]:
nums=[]
def a(head):
if not head:
return
nums.append(head.val)
a(head.left)
a(head.right)
a(root)
return nums
'''先序,遍历'''
# 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: Optional[TreeNode]) -> List[int]:
arr=[]
if root:
nums=[root]
while nums:
head=nums.pop()
arr.append(head.val)
if head.right is not None:
nums.append(head.right)
if head.left is not None:
nums.append(head.left)
return arr
'''中序,迭代'''
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
arr1=[]
if root is None:
return None
arr=[]
while len(arr)!=0 or root is not None:
if root is not None:
arr.append(root)
root=root.left
else:
root=arr.pop()
arr1.append(root.val)
root=root.right
return arr1
'''中序,递归'''
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
arr1=[]
def a(head):
if head is None:
return
a(head.left)
arr1.append(head.val)
a(head.right)
a(root)
return arr1
'''后序.递归'''
# 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: Optional[TreeNode]) -> List[int]:
arr1=[]
def a(head):
if head is None:
return
a(head.left)
a(head.right)
arr1.append(head.val)
a(root)
return arr1
'''后序,迭代'''
# 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: Optional[TreeNode]) -> List[int]:
arr=[]
arr1=[]
if root:
nums=[root]
while nums:
head=nums.pop()
arr.append(head.val)
if head.left is not None:
nums.append(head.left)
if head.right is not None:
nums.append(head.right)
for i in arr[::-1]:
arr1.append(i)
return arr1
前序遍历:中左右
中序遍历:左中右
后序遍历:左右中
所以后序遍历只要把前序遍历左右互换后倒过来就行
1.17
二叉树层序遍历(广度)
# 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 levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
nums=[] #每一层数据
nums1=[] #总数据
if root:
que=[root] #头节点入栈
while que:
for _ in range(len(que)):
q=que.pop(0) #先进的先出
if q:
'''节点不为空将节点数据加入数组,并且如果左右数据不为空按照左-右的顺序压入栈'''
nums.append(q.val)
if q.left:
que.append(q.left)
if q.right:
que.append(q.right)
nums1.append(list(nums)) #保存数据
nums=[] #初始化每一层的数据
return list(reversed(nums1)) #按照题目要求反转列表
这题只要根据上题,层次遍历完后输出每层数据最后一个就行
class Solution:
def rightSideView(self, root: TreeNode) -> List[int]:
# Definition for a binary tree node.
nums=[]
nums1=[]
if root:
que=[root]
while que:
for _ in range(len(que)):
q=que.pop(0)
if q:
nums.append(q.val)
if q.left:
que.append(q.left)
if q.right:
que.append(q.right)
nums1.append(nums[-1])
nums=[]
return nums1
这题和上题类似
将 nums1.append(nums[-1]) 改为 nums1.append(sum(nums)/len(nums))
pass
类似,nums1.append(nums[-1])—>nums1.append(max(nums)))
pass
"""
# Definition for a Node.
class Node:
def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
self.val = val
self.left = left
self.right = right
self.next = next
"""
class Solution:
def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
if root:
que=[root]
while que:
n=len(que)
for i in range(n):
head=que.pop(0)
if head.left:
que.append(head.left)
if head.right:
que.append(head.right)
if i==n-1:
break
head.next=que[0]
return root
多叉树的层次遍历
# 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 levelOrder(self, root):
nums = []
num = []
if not root:
return nums
q = [root]
while q:
for _ in range(len(q)):
cur = q.pop(0)
num.append(q.val)
if cur.children:
q.append(cur.children)
nums.append(num)
num = []
return nums
1.18
'''排列组合出所有可能,最后去重,再干掉所有不合法的
方法和思路是对的
但由于Permutations,全排列的时间复杂度(O(n*n!)
所以这个我自己想的简单粗暴的方法百分百超时
'''
class Solution:
def generateParenthesis(self, n):
strs=["(",')']*n
from itertools import permutations
kh=list(set(list(permutations(strs,n*2))))
s=[]
def ishf(s): #前面造的轮子,直接拿过来用了
sta =[]
for i in s:
if i== '(':
sta.append(')')
elif len(sta) == 0 or sta[-1] != i:
return False
else:
sta.pop()
return True if not sta else False
for i in kh:
if ishf(i):
s.append(''.join(i))
return s
1.19
# 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 maxDepth(self, root: Optional[TreeNode]) -> int:
cot=0
if root:
nums=[root]
while nums:
for i in range(len(nums)):
num=nums.pop(0)
if num:
if num.left:
nums.append(num.left)
if num.right:
nums.append(num.right)
cot+=1
return cot
上一题只要跑完层序遍历后返回一共循环多少次就行
这题检测到当左右节点都为空时就返回
非递归
# 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 minDepth(self, root: TreeNode) -> int:
if root == None:
return 0
que = [(root,1)] //设置根节点
while que:
cur, depth = que.pop(0)
if cur.left == None and cur.right == None:
return depth
#先左子节点,由于左子节点没有孩子,则就是这一层了
if cur.left:
que.append((cur.left,depth + 1))
if cur.right:
que.append((cur.right,depth + 1))
return 0
二叉树翻转
前序遍历或者后序遍历都行,边遍历边交换
# 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 invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return None
root.left,root.right=root.right,root.left //交换
self.invertTree(root.left) //左
self.invertTree(root.right) //右
return root
1.20
了解一下回溯算法
个人理解的回溯算法是,这一步走不通,就返回去走另一步,直到走完所有可能,有点像二叉树的遍历,走到最低端,返回上一步,走另一边,直到走完所有节点,回溯的本质是穷举,穷举所有可能,然后选出我们想要的答案
回溯是递归的副产品,只要有递归就会有回溯。
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
nums1=[]
nums2=[]
def vd(startnum):
if len(nums2)==k: //终止条件
nums1.append(list(nums2))
return
for i in range(startnum,n+1)://宽度遍历
nums2.append(i)
vd(i+1) //深度遍历
nums2.pop() //删除这步,走另一步,回溯算法
vd(1)
return nums1
因为有for循环最后pop的存在,所有每一次for遍历都可以看作nums2没有加任何东西,重新开始遍历,每一次递归nums2内都会多一个数,直到满足条件跳出递归
class Solution:
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
nums1=[]
nums2=[]
def vd(start):
if sum(nums2)==n and len(nums2)==k: //因为这题要满足两个条件,所有只有两个条件同时满足才返回
nums1.append(list(nums2))
return
if len(nums2)==k or sum(nums2)>=n: //如果只满足一个条件,那么另外一个条件不可能满足,直接返回
return
for i in range(start,10):
nums2.append(i)
vd(i+1)
nums2.pop()
vd(1)
return nums1
1.21
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
nums=[]
nums1=[]
def vd(start):
if sum(nums1)==target:
nums.append(list(nums1))
return
if sum(nums1)>target:
return
for i in range(start,len(candidates)):
nums1.append(candidates[i])
vd(i) //可以重复选取,所以不需要+1
nums1.pop() //回溯
vd(0)
return nums
比起上题,需要去重,
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
nums=[]
nums1=[]
candidates.sort()
def vd(start):
if sum(nums1)==target:
nums.append(list(nums1))
return
if sum(nums1)>target:
return
for i in range(start,len(candidates)):
nums1.append(candidates[i])
if i > start and candidates[i] in candidates[0:i]:#遇到重复的跳过一轮循环
continue
vd(i+1)
nums1.pop()
vd(0)
return nums
1.22
分割问题,和组合问题类似,组合问题选取了一个以后,下一个就要从这个数的下一个开始选取,分割问题割出一段后,再割出下一段就要从剩下的第一个开始
class Solution:
def partition(self, s):
strs=[]
strs1=[]
def vd(start):
if start >= len(s): #字符串被切完后返回
strs.append(list(strs1))
return
for i in range(start,len(s)):
temp = s[start:i + 1] #切割字符串
if temp == temp[::-1]: # 判断回文串,若反序和正序相同,意味着这是回文串
strs1.append(temp)
vd(i + 1) #从切割后的下一处继续切割,直到字符串被切完
strs1.pop()
else:
continue
vd(0)
return strs
这题主要是三个点号的位置,分段的数字大小都要是0~255之间,且不能含有前导零,所以需要一个判断是否是有效数段的
class Solution:
def restoreIpAddresses(self, s):
nums_ip=[]
point=0 #点号数量,如果有三个点号说明分割完成
def isva(s,start,end): #判断是否满足三个条件
if start > end:
return False
if s[start] == '0' and start != end:
return False
if not 0 <= int(s[start:end+1]) <= 255:
return False
return True
def vd(s,start,point):
if point==3: #递归结束条件
if isva(s,start,len(s)-1):
nums_ip.append(s[:])
return
for i in range(start,len(s)):
if isva(s,start,i):
s=s[:i+1]+'.'+s[i+1:] #添加点号
vd(s,i+2,point+1) #因为存在点号,所以每次起始位置都要+2,每次递归都新增一个点号
s = s[:i + 1] + s[i + 2:] #删除点号,回溯
else:
break
vd(s,0,point)
return nums_ip
子集数量就是从0到数组长度每个数多少的组合,
class Solution:
def subsets(self, nums: list):
nums1 = []
nums2 = []
def vd(start,k):
if len(nums2)==k:
nums1.append(list(nums2))
return
for i in range(start,len(nums)):
nums2.append(nums[i])
vd(i + 1,k)
nums2.pop()
for i in range(len(nums)+1):#从0开始遍历到数组长度,i的个数的组合全部加进列表任何返回就行
vd(0,i)
return nums1
1.23
直接导入itertools包,一步解决
pass
全排列,不放回有序组合,只要每一次都从头开始选就行,由于从头开始选会选到重复的,所以遇到重复的直接跳过就行
在这里插入代码片
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
nums1 = []
nums2 = []
def vd():
if len(nums2)==len(nums):
nums1.append(list(nums2))
return
for i in range(len(nums)):
if nums[i] in nums2: #如果已经出现过,则跳过本层循环
continue
nums2.append(nums[i])
vd()
nums2.pop()
vd()
return nums1
回溯算是学到了点皮毛,年后再去刷hard题
复习一下链表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeElements(self, head: ListNode, val: int) -> ListNode:
head = ListNode(next=head)
cur = head
while cur.next:
if cur.next.val == val:
cur.next = cur.next.next #让cur.next直接指向下一个节点,删除cur.next节点
else:
cur = cur.next
return head.next
class Node:
def __init__(self, val):#节点
self.val = val
self.next = None
class MyLinkedList:
def __init__(self, head):
self.head = head
def get(self, index: int) -> int:
cur = self.head
if cur:
return -1
cot = 0
while cot != index:
if cur.next is None:
return -1
cur = cur.next
cot += 1
return cot
def addAtHead(self, val: int) -> None:
node = Node(val)
node.next = self.head #将头节点向下移动
self.head = node #添加到头节点
def addAtTail(self, val: int) -> None:
node = Node(val)
if self.head is None:
self.head = Node
else:
cur = self.head
while cur.next: #遍历到尾部
cur = cur.next
cur.next = node #添加进尾部
def addAtIndex(self, index: int, val: int) -> None:
cot = 0
node = Node(val)
if index <= 0:
self.addAtHead(val)
else:
cur = self.head
if cur is None:
self.head = node
return
while cot != index-1:
cur = cur.next
cot += 1
if cur.next is None:
return
node.next = cur.next
cur.next = node
def deleteAtIndex(self, index: int) -> None:
cot = 0
cur = self.head
while cot != index-1:
if cur.next is None:
return
cur = cur.next
cot += 1
cur.next=cur.next.next
写这种老长老长的题目真折磨人,链表自己试过,都能完成功能,但是不知道这种题应该怎么提交,点提交就报错
1.25
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if not root or root == p or root == q: #如果找到了 节点p或者q,或者遇到空节点,就返回
return root
left = self.lowestCommonAncestor(root.left, p, q) #后序遍历,最先处理的一定是叶子节点
right = self.lowestCommonAncestor(root.right, p, q)
if left and right: #遇到空节点直接返回
return root
if left:
return left
return right
和层序遍历一样,只要统计最后的个数就行
class Solution:
def countNodes(self, root: TreeNode) -> int:
nums=[]
nums1=[]
if root:
que=[root]
while que:
for _ in range(len(que)):
q=que.pop(0)
if q:
nums.append(q.val)
if q.left:
que.append(q.left)
if q.right:
que.append(q.right)
nums1.append(nums)
nums=[]
else : return
sum_=[]
for i in nums1:
sum_.append(len(i))
return sum(sum_)