文章目录
leetcode 310. Minimum Height Trees
由于一张图最多有两个最小高度树,所以可以这么写:
方法一:
思路很简单,但是比较耗时,先把图遍历一遍,用字典存下每个节点的所有支路;构建节点集合,如果集合的数量大于2,说明要删除一些节点,先从叶节点开始,从集合中删除叶节点的同时,刚刚维护的字典也需要把这些通往叶节点的支路删掉,得到一个简化版的图,删完一遍叶节点之后,s集合的元素如果仍旧大于2,重复继续删。 参考
class Solution:
def findMinHeightTrees(self, n: int, edges: List[List[int]]) -> List[int]:
import collections
# defaultdict无需初始化
d = collections.defaultdict(set) #字典每一个key对应的value是set集合
for x,y in edges:
d[x].add(y) #集合的add操作
d[y].add(x)
s = set(range(n)) #构建节点的集合
while(len(s)>2): # 满足最小生成树的节点个数不可能超过2
leaves = set(i for i in s if len(d[i])==1) #只有一条支路的就是叶节点
s -= leaves
for i in leaves: #要删的节点号
for j in d[i]:
d[j].remove(i)
return list(s)
方法二:
只改变了一点点,但是代码运行时间提升了很多,在while循环里维护一个tmp集合,每轮更新叶节点。
class Solution:
def findMinHeightTrees(self, n: int, edges: List[List[int]]) -> List[int]:
import collections
# defaultdict无需初始化
d = collections.defaultdict(set) #字典每一个key对应的value是set集合
for x,y in edges:
d[x].add(y) #集合的add操作
d[y].add(x)
s = set(range(n))
leaves = set(i for i in s if len(d[i])==1) #只有一条支路的就是叶节点
while(len(s)>2): # 满足最小生成树的节点个数不可能超过2
tmp = set()
s -= leaves
for i in leaves: #要删的节点号
for j in d[i]:
d[j].remove(i)
if len(d[j])==1:
tmp.add(j)
leaves = tmp
return list(s)
leetcode 802. Find Eventual Safe States
分析:何谓安全,首先,只有流入没有流出的肯定是安全的(就是graph里面的空list),其次,只有一个流出分支,且该分支正好流入安全节点,那么该节点也是安全节点。(如果有多个流出分支,其中一个是流向安全节点的不算)
方法一:
先构建两个字典,一个用来存每个节点流出几个分支,一个用来存流入每个节点的分支列表。第二步,维护一个列表,先存入那些没有流入的节点,循环安全节点列表,找到那些只有一个流出分支,且是流入安全节点的节点,也添进安全列表里。该方法耗时 Runtime: 240 ms, faster than 42.53%
参考
class Solution:
def eventualSafeNodes(self, graph: List[List[int]]) -> List[int]:
out_degree = collections.defaultdict(int) # 用来存每个节点流出几个分支(只是一个数字)
in_nodes = collections.defaultdict(list) # 用来流入每个节点的分支列表(是一个list)
n = len(graph)
queue, res = [], []
for i in range(n): #先遍历一遍,构建上述两个dict
out_degree[i] = len(graph[i])
if out_degree[i]!=0:
for j in graph[i]:
in_nodes[j].append(i)
else:
queue.append(i)
while queue:
tmp = queue.pop(0)
res.append(tmp)
if len(in_nodes[tmp]):
for i in in_nodes[tmp]:
out_degree[i] -= 1
if out_degree[i] == 0:
queue.append(i)
return sorted(res)
方法二:
深度优先遍历,维护一个visited数组,长度为节点个数,初始化为0,如果是安全的则为1,不安全为-1。运行时间Runtime: 180 ms, faster than 83.62% 。 参考
class Solution:
def eventualSafeNodes(self, graph: List[List[int]]) -> List[int]:
visited = [0] * len(graph) # 初始化为0,1表示安全,-1表示不安全
res = []
for i in range(len(graph)):
if self.dfs(graph,visited,i):
res.append(i)
return res
def dfs(self, graph, visited,i):
if visited[i]!=0:
return visited[i] == 1
visited[i] = -1
for j in graph[i]:
if not self.dfs(graph,visited,j):
return False
visited[i] = 1
return True
leetcode 785. Is Graph Bipartite?
先来一个discuss里的算法,思路是创建一个空字典,如果访问过该节点,就将节点加入字典中,通过判断节点是否在字典中,来保证每个节点的graph只访问一次!参考
class Solution:
def isBipartite(self, graph: List[List[int]]) -> bool:
visited = {}
def dfs(i):
for j in graph[i]:
if j in visited:
if visited[j] == visited[i]:
return False
else:
visited[j] = 1 - visited[i]
if not dfs(j):
return False
return True
for i in range(len(graph)):
if i not in visited:
visited[i] = 0
if not dfs(i):
return False
return True
自己的思路:
我是通过设置visit数组来判断是否经过该节点,初始化为0,第一次经过就设置为1,跟它对应的节点设置成-1,耗时更短,依旧使用深度优先遍历。
class Solution:
def isBipartite(self, graph: List[List[int]]) -> bool:
visited= [0] * len(graph) # 0表示未访问,1表示集合1,-1表示集合2
def dfs(i):
for j in graph[i]:
if visited[j]:
if visited[j] == visited[i]:
return False
else:
visited[j] = 0 - visited[i]
if not dfs(j):
return False
return True
for i in range(len(graph)):
if visited[i] == 0:
visited[i] = 1
if not dfs(i):
return False
return True
leetcode 399. Evaluate Division
这一题有点没看懂,先把参考答案放在这里,过几天再看一遍! 参考
class Solution:
def calcEquation(self, equations, values, queries):
def dfs(x,y,visited):
if x==y:
return 1.0
visited.add(x)
for n in d[x]:
if n in visited:
continue
visited.add(n)
tmp = dfs(n,y,visited)
if tmp > 0:
return tmp * d[x][n]
return -1.0
d = collections.defaultdict(dict)
for (a,b), value in zip(equations, values):
d[a][b] = value
d[b][a] = 1.0 / value
res = []
for x,y in queries:
if x not in d or y not in d:
res.append(-1.0)
else:
res.append(dfs(x,y,set()))
return res
leetcode 743. Network Delay Time
最短路径问题,迪杰特斯拉算法求解即可,代码参考这里
Runtime: 80 ms, faster than 98.12%
class Solution:
def networkDelayTime(self, times: List[List[int]], N: int, K: int) -> int:
from collections import defaultdict
Q = set(range(N))
graph = defaultdict(dict)
for u, v, w in times:
graph[u-1][v-1] = w
D = [float('Inf')] * N
D[K-1] = 0
while len(Q):
u = None
for w in Q:
if u == None or D[w] < D[u]:
u = w
Q.remove(u)
for w in graph[u]:
if D[u] + graph[u][w] < D[w]:
D[w] = D[u] + graph[u][w]
res = max(D)
return -1 if res == float('Inf') else res