目录
堆盘子
设想有一堆盘子,堆太高可能会倒下来。因此,在现实生活中,盘子堆到一定高度时,我们就会另外堆一堆盘子。请实现数据结构SetOfStacks,模拟这种行为。SetOfStacks应该由多个栈组成,并且在前一个栈填满时新建一个栈。此外,SetOfStacks.push()和SetOfStacks.pop()应该与普通栈的操作方法相同(也就是说,pop()返回的值,应该跟只有一个栈时的情况一样)。 进阶:实现一个popAt(int index)方法,根据指定的子栈,执行pop操作。
当某个栈为空时,应当删除该栈。当栈中没有元素或不存在该栈时,pop,popAt 应返回 -1.
要点在于处理边界情形,利用好list中的pop()和append()方法。代码如下:
class StackOfPlates:
def __init__(self, cap: int):
self.cap = cap
self.array = []
def push(self, val: int) -> None:
# 处理边界情况:cap == 0 不让push
if self.cap == 0:
return
if not self.array or len(self.array[-1]) >= self.cap:
self.array.append([val])
else:
self.array[-1].append(val)
def pop(self) -> int:
val = -1
if self.array and self.array[-1]:
val = self.array[-1].pop()
if not self.array[-1]: self.array.pop()
return val
def popAt(self, index: int) -> int:
val = -1
if len(self.array) >= index + 1:
val = self.array[index].pop()
if not self.array[index]: self.array.pop(index)
return val
栈排序
辅助栈解法
维护两个单调递减的栈,并且stack的最大元素要小于helpstack的最小元素,即helpstack的栈顶>=stack[0]
优先考虑stack,
如果val<=self.stack[-1],直接添加即可
如果val>self.stack[-1],考虑stack[0]与val的关系,
如果stack[0]>val,左边删除stack加入到helpstack
如果stack[0]<val,考虑与helpstack的关系,
如果stack为空再考虑helpstack:
与上面同理
最后如果都为空,直接添加到stack即可
总之,每一次push操作均要保证两点:
1、两个单调递减的栈
2、helpstack[-1]>=stack[0]
class SortedStack:
def __init__(self):
from collections import deque
#维持两个单调递减的栈,并且stack的最大元素要小于helpstack的最小元素,即helpstack的栈顶>=stack[0]
self.helpstack = deque()
self.stack = deque()
def push(self, val: int) -> None:
if self.stack:
if val <= self.stack[-1]:
self.stack.append(val)
return
# 如果val>self.stack[-1],考虑stack[0]与val的关系
while self.stack and val < self.stack[0]:
temp = self.stack.popleft()
self.helpstack.append(temp)
# 如果val>=self.stack[0],考虑helpstack[-1]与val的关系
while self.helpstack and val > self.helpstack[-1]:
temp = self.helpstack.pop()
self.stack.appendleft(temp)
self.stack.appendleft(val)
elif self.helpstack:
while self.helpstack and val > self.helpstack[-1]:
temp = self.helpstack.pop()
self.stack.appendleft(temp)
self.helpstack.append(val)
else:
self.stack.append(val)
def pop(self) -> None:
if self.stack:
self.stack.pop()
elif self.helpstack:
self.helpstack.pop()
else:
return
def peek(self) -> int:
if self.stack:
return self.stack[-1]
elif self.helpstack:
return self.helpstack[-1]
else:
return -1
def isEmpty(self) -> bool:
return len(self.stack)+len(self.helpstack)==0
节点间通路
节点间通路。给定有向图,设计一个算法,找出两个节点之间是否存在一条路径。
邻接表和BFS(广度优先搜索)算法
class Solution:
def findWhetherExistsPath(self, n: int, graph: List[List[int]], start: int, target: int) -> bool:
# 构建邻接表
link_table = [[] for i in range(n)]
for edge in graph:
link_table[edge[0]].append(edge[1])
visited = [0]*n
# BFS
que = [start]
while que:
cur_node = que.pop()
if target in link_table[cur_node]:
return True
for node in link_table[cur_node]:
if visited[node] == 0:
que.insert(0, node)
visited[cur_node] = 1
return False
邻接表和DFS(深度优先搜索)算法
class Solution:
def findWhetherExistsPath(self, n: int, graph: List[List[int]], start: int, target: int) -> bool:
# 邻接表
edges = collections.defaultdict(list)
for i in graph:
edges[i[0]].append(i[1])
# DFS
def DFS(start, target, visited):
if start == target:
return True
if visited[start]:
return False
visited[start] = True
judge = False
for i in edges[start]:
if not visited[i]:
judge = judge or DFS(i, target, visited)
return judge
visited = [False]*n
return DFS(start, target, visited)
BFS算法和DFS算法相比较,两者内存消耗相近,但DFS算法运行时间较短。
合法二叉搜索树
二叉搜索树,又称二叉排序树,它的特点是它的中序遍历一定是一个单调递增数列。
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
nodes =[]
def search(root):
if root:
search(root.left)
nodes.append(root.val)
search(root.right)
search(root)
return nodes == sorted(set(nodes))
首个共同祖先
设计并实现一个算法,找出二叉树中某两个节点的第一个共同祖先。不得将其他的节点存储在另外的数据结构中。注意:这不一定是二叉搜索树。
递归解法
- 假设我们从跟结点开始,采用 DFS 向下遍历,如果当前结点到达叶子结点下的空结点时,返回空;如果当前结点为 p 或 q 时,返回当前结点;
- 这样,当我们令 left = self.lowestCommonAncestor(root.left, p, q) 时,如果在左子树中找到了 p 或 q,left 会等于 p 或 q,同理,right 也是一样;
- 然后我们进行判断:如果 left 为 right 都不为空,则为情况 1;如果 left 和 right 中只有一个不为空,说明这两个结点在子树中,则根节点到达子树再进行寻找。
代码如下:
class Solution:
def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:
if not root or root == p or root == q:
return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
if left and right:
return root
return left if left else right
二叉搜索树序列
递归解法
使用一个queue存储下个所有可能的节点,然后选择其中一个作为path的下一个元素,递归直到queue元素为空,将对应的path加入结果中。由于二叉搜索树没有重复元素, 而且每次递归的使用元素的顺序都不一样, 所以自动做到了去重。
class Solution:
def BSTSequences(self, root: TreeNode) -> List[List[int]]:
if not root:
return [[]]
res = []
def findPath(cur, q, path):
if cur.left:
q.append(cur.left)
if cur.right:
q.append(cur.right)
if not q:
res.append(path)
return
for i, nex in enumerate(q):
newq = q[:i] + q[i + 1:]
findPath(nex, newq, path + [nex.val])
findPath(root, [], [root.val])
return res
检查子树
检查子树。你有两棵非常大的二叉树:T1,有几万个节点;T2,有几万个节点。设计一个算法,判断 T2 是否为 T1 的子树。
如果 T1 有这么一个节点 n,其子树与 T2 一模一样,则 T2 为 T1 的子树,也就是说,从节点 n 处把树砍断,得到的树与 T2 完全相同。
双重dfs解法
第一重:在 t1 中找到 t2 的起点。先判断 t1 当前节点,如果不对就判断 t1 左子树和 t1 右子树。
第二重:从找到的起点开始判断剩下的点,t1 和 t2 同步左右子树搜索。
class Solution:
def checkSubTree(self, t1: TreeNode, t2: TreeNode) -> bool:
if not t1:
return not t2
if not t2:
return True
return self.dfs(t1, t2) or self.checkSubTree(t1.left, t2) or self.checkSubTree(t1.right, t2)
def dfs(self, t1, t2):
if not t2:
return True
elif not t1:
return False
elif t1.val != t2.val:
return False
else:
return self.dfs(t1.left, t2.left) and self.dfs(t1.right, t2.right)
求和路径
递归解法
给定一棵二叉树,其中每个节点都含有一个整数数值(该值或正或负)。设计一个算法,打印节点数值总和等于某个给定值的所有路径的数量。注意,路径不一定非得从二叉树的根节点或叶节点开始或结束,但是其方向必须向下(只能从父节点指向子节点方向)。
pathSum所求的是从root节点及以下节点开始的路径数,而path函数所求的只是从root节点开始的路径数,利用递归方法,代码如下:
class Solution:
def pathSum(self, root: TreeNode, sum: int) -> int:
if not root:
return 0
return self.path(root,sum)+self.pathSum(root.right,sum)+self.pathSum(root.left,sum)
def path(self, root, sum):
if not root:
return 0
res = 0
if root.val == sum:
res += 1
res += self.path(root.left, sum-root.val)
res += self.path(root.right, sum-root.val)
return res