对于我们常用的 Python 我们使用 stack=[] 就可以了。

用栈实现队列

直白地使用 helpStack

  1. class MyQueue:
  2. def __init__(self):
  3. self.stack=[]
  4. self.helpStack=[]
  5. def push(self, x: int) -> None:
  6. self.stack.append(x)
  7. def pop(self) -> int:
  8. if self.helpStack:return self.helpStack.pop()
  9. while self.stack:
  10. self.helpStack.append(self.stack.pop())
  11. return self.helpStack.pop()
  12. def peek(self) -> int:
  13. if self.helpStack:return self.helpStack[-1]
  14. while self.stack:
  15. self.helpStack.append(self.stack.pop())
  16. return self.helpStack[-1]
  17. def empty(self) -> bool:
  18. return not self.stack and not self.helpStack

字符串解码

类似栈的处理 - 一步一步写下来并不难,需要注意数字代表的次数重叠的情况

测试用例: "3[z]2[2[y]pq4[2[jk]e1[f]]]ef"

  1. class Solution:
  2. def decodeString(self, s: str) -> str:
  3. stack,result,=[],""
  4. for char in s:
  5. if '0'<=char<='9':
  6. stack.append(char)
  7. elif char=='[':
  8. stack.append('[')
  9. elif char==']':
  10. temp,times="",""
  11. while stack and stack[-1]!='[':
  12. temp=stack.pop()+temp
  13. stack.pop()
  14. while stack and '0'<=stack[-1]<='9':
  15. times=stack.pop()+times
  16. temp=temp*int(times)
  17. for i in range(len(temp)):
  18. stack.append(temp[i])
  19. else:
  20. if not stack:
  21. result+=char
  22. continue
  23. stack.append(char)
  24. #print(char,result,stack)
  25. return result+''.join(stack)

最小栈

  1. class MinStack:
  2. def __init__(self):
  3. self.min=sys.maxsize
  4. self.stack=[]
  5. def push(self, x: int) -> None:
  6. self.stack.append(x-self.min)
  7. if x<self.min:
  8. self.min=x
  9. def pop(self) -> None:
  10. target=self.stack.pop()
  11. if target<0:
  12. self.min=self.min-target
  13. def top(self) -> int:
  14. if self.stack:
  15. target=self.stack[-1]
  16. if target<0:return self.min
  17. return target+self.min
  18. def getMin(self) -> int:
  19. return self.min

有效的括号

注意无效情况的快速判断 - 剪枝

  1. class Solution:
  2. def isValid(self, s: str) -> bool:
  3. stack=[]
  4. pairs={'(':')','[':']','{':'}'}
  5. for char in s:
  6. if char in pairs:
  7. stack.append(char)
  8. else:
  9. if len(stack)==0:return False
  10. if pairs[stack[-1]]!=char:return False
  11. else:stack.pop()
  12. return len(stack)==0

每日温度

栈里面存储的是递减的元素 - 栈题型中:里面存储元素的特异性

  1. class Solution:
  2. def dailyTemperatures(self, T: List[int]) -> List[int]:
  3. if not T:return 0
  4. length=len(T)
  5. stack=[]
  6. result=[0 for _ in range(length)]
  7. for idx,temp in enumerate(T):
  8. if len(stack)==0:
  9. stack.append(idx)
  10. continue
  11. if temp<=T[stack[-1]]:
  12. stack.append(idx)
  13. continue
  14. while stack and temp>T[stack[-1]]:
  15. result[stack[-1]]=idx-stack[-1]
  16. stack.pop()
  17. stack.append(idx)
  18. return result

逆波兰表达式求值

注意 Python除法 的细节,-6//12=-1,所以最后使用了 int(op1/op2)

  1. class Solution:
  2. def evalRPN(self, tokens: List[str]) -> int:
  3. stack=[]
  4. operations=['+','-','*','/']
  5. for element in tokens:
  6. if element in operations:
  7. op2=stack.pop()
  8. op1=stack.pop()
  9. if element=='+':stack.append(op1+op2)
  10. elif element=='-':stack.append(op1-op2)
  11. elif element=='*':stack.append(op1*op2)
  12. elif element=='/':stack.append(int(op1/op2))
  13. else:
  14. stack.append(int(element))
  15. return stack[-1]

DFS

在我们到达最深的结点之后,我们会回溯并尝试另一条路径。

DFS模板 I

这个模板是我最开始写题目时候最顺手的一个模板:

  • 代码简洁易懂,对节点的判断在进入函数之后
  • 同时也可以产生出新的版本:
    • 在进入递归之前首先对于节点的有效性进行判断
    • 对于递归的出口仍然保留在进入递归之后,不僭越进行判断
    • 这样减少不必要的函数调用,同时能够使得递归形式更加简洁
  1. visited=[[False for i in range(m)] for j in range(n)]
  2. def dfs(curr,target):
  3. if curr is invalid or curr is visited:return
  4. if curr==target:result.append(curr)
  5. visited[curr]=True
  6. #对当前节点其他操作
  7. Some_operation()
  8. for next in neibours:
  9. dfs(next,target)
  10. #如果回溯
  11. #visited[curr]=False

判断版本:主要是担心判断的时候不充分,或者判断太复杂

  1. visited=[[False for i in range(m)] for j in range(n)]
  2. def dfs(curr,target):
  3. if curr==target:result.append(curr)
  4. visited[curr]=True
  5. #对当前节点其他操作
  6. Some_operation()
  7. for next in neibours:
  8. if next is valid and next is not visited:
  9. dfs(next,target)
  10. #如果回溯
  11. #visited[curr]=False

岛屿数量

  1. class Solution:
  2. def numIslands(self, grid: List[List[str]]) -> int:
  3. if not grid or not grid[0]:return 0
  4. m,n=len(grid),len(grid[0])
  5. directions=[(1,0),(-1,0),(0,1),(0,-1)]
  6. def dfs(r,c):
  7. if r<0 or r>=m or c<0 or c>=n or grid[r][c]=='0' :return
  8. grid[r][c]='0'
  9. for d in directions:
  10. dfs(r+d[0],c+d[1])
  11. count=0
  12. for i in range(m):
  13. for j in range(n):
  14. if grid[i][j]=='1':
  15. count+=1
  16. dfs(i,j)
  17. return count

克隆图

克隆问题都可以是类似的思路。

  1. class Solution:
  2. def __init__(self):
  3. self.visited={}
  4. def cloneGraph(self, node: 'Node') -> 'Node':
  5. if not node:return node
  6. if node in self.visited:return self.visited[node]
  7. clone_node=Node(node.val,[])
  8. self.visited[node]=clone_node
  9. if node.neighbors:
  10. clone_node.neighbors=[self.cloneGraph(i) for i in node.neighbors]
  11. return clone_node

目标和

展示两种方法:

  1. 纯正的DFS但是超时了,可能大量重复计算了

    1. class Solution:
    2. def findTargetSumWays(self, nums: List[int], S: int) -> int:
    3. if not nums:return 0
    4. self.count,self.length=0,len(nums)
    5. def dfs(curr,bit):
    6. if curr==0 and bit==self.length:
    7. self.count+=1
    8. return
    9. if bit==self.length:return
    10. dfs(curr+nums[bit],bit+1)
    11. dfs(curr-nums[bit],bit+1)
    12. dfs(-S,0)
    13. return self.count
  2. DFS要学会 类似树状展开 的计算方式

    1. class Solution:
    2. def findTargetSumWays(self, nums: List[int], S: int) -> int:
    3. if not nums:return 0
    4. self.visited,self.length={},len(nums)
    5. def dfs(curr,i):
    6. if i<self.length and (curr,i) not in self.visited:
    7. self.visited[(curr,i)]=dfs(curr+nums[i],i+1)+dfs(curr-nums[i],i+1)
    8. return self.visited.get((curr,i),int(curr==S))
    9. return dfs(0,0)

DFS模板 II

避免递归深度太高,堆栈溢出 -> 使用BFS,或者显式栈实现DFS

  1. def DFS(root,target):
  2. visited=set()
  3. stack=[root]
  4. while stack:
  5. curr=stack[-1]
  6. if curr==target:return True
  7. for next in neibours:
  8. if next is not in visited:
  9. stack.append(next)
  10. visited.add(next)
  11. remove curr from stack
  12. return False

中序遍历

  1. class Solution:
  2. def inorderTraversal(self, root: TreeNode) -> List[int]:
  3. if not root:return []
  4. result,stack=[],[(root,0)]
  5. while stack:
  6. node,times=stack.pop()
  7. if not node:continue
  8. if times==1:
  9. result.append(node.val)
  10. stack.append((node.right,0))
  11. continue
  12. stack.append((node,1))
  13. stack.append((node.left,0))
  14. return result

图像渲染

  1. class Solution:
  2. def floodFill(self, image: List[List[int]], sr: int, sc: int, newColor: int) -> List[List[int]]:
  3. if not image or not image[0]:return image
  4. rawColor=image[sr][sc]
  5. if rawColor==newColor:return image
  6. m,n=len(image),len(image[0])
  7. visited=[[False for i in range(n)] for j in range(m)]
  8. directions=[(1,0),(-1,0),(0,1),(0,-1)]
  9. def dfs(r,c):
  10. if r<0 or r>=m or c<0 or c>=n or visited[r][c] or image[r][c]!=rawColor:return
  11. visited[r][c]=True
  12. image[r][c]=newColor
  13. for d in directions:
  14. dfs(r+d[0],c+d[1])
  15. dfs(sr,sc)
  16. return image

这个再写一个版本看看【版本的区别主要是递归前是否先判断可行性】

  1. class Solution:
  2. def floodFill(self, image: List[List[int]], sr: int, sc: int, newColor: int) -> List[List[int]]:
  3. if not image or not image[0]:return image
  4. rawColor=image[sr][sc]
  5. if rawColor==newColor:return image
  6. m,n=len(image),len(image[0])
  7. visited=[[False for i in range(n)] for j in range(m)]
  8. directions=[(1,0),(-1,0),(0,1),(0,-1)]
  9. def dfs(r,c):
  10. visited[r][c]=True
  11. image[r][c]=newColor
  12. for d in directions:
  13. newR,newC=r+d[0],c+d[1]
  14. if 0<=newR<m and 0<=newC<n and not visited[newR][newC] and image[newR][newC]==rawColor:
  15. dfs(newR,newC)
  16. dfs(sr,sc)
  17. return image