bfs_leetcode 310 最小高度树
由于遍历每一个节点为根节点树的高度,再去求最小时间复杂度为O(n^2),超时
class Solution: def findMinHeightTrees(self, n: int, edges: List[List[int]]) -> List[int]: def find_height(node,result): queue=collections.deque() visit=[0 for _ in range(n)] queue.append(node) visit[node]=1 step=-1 while queue: size=len(queue) for _ in range(size): x=queue.popleft() for item in edges: if item[0]==x and visit[item[1]]!=1: queue.append(item[1]) visit[item[1]]=1 elif item[1]==x and visit[item[0]]!=1: queue.append(item[0]) visit[item[0]]=1 step+=1 if step not in result: result[step]=[node] else: result[step].append(node) return result minvalue=float('inf') result={} for i in range(n): result=find_height(i,result) for i in range(n): if i in result.keys(): return result[i]
所以反过来思考,从最外层向最里层遍历,也就是从叶子节点向根节点进行bfs,将出度为1的节点都入列,然后排除。最后当所有节点都在同一层,证明他们的高度都是一样的,所以均为答案。也就是当queue的长度等于当前没有遍历的剩余元素。
找到数的最小高度,那么就像层序遍历一样,从最外层一层一层往里数,当剩下的元素均在同一层时,这些元素就是最小层的元素了。而且是只剩下1,2个点,因为如果有多的点就会形成新的层。
具体实现方式和按层分组的层序遍历类似,先把最外层入队,然后每次循环队中全部元素。
找到这个元素未遍历过的相邻元素并入队。
直至一轮开始时剩余元素数量等于队中元素数量就不再遍历,因为这些就是全部能作为答案的元素了(也就是最中间层的元素);
很显然,如果剩余元素比队中的多,那么说明还有元素没有遍历到,需要继续遍历;
剩余元素不会比队中的少,因为入队的元素是唯一且为剩余元素的。
作者:meng-li-ye-tian-xing
链接:https://leetcode-cn.com/problems/minimum-height-trees/solution/c-you-wai-zhi-nei-de-ceng-xu-bian-li-by-dnu8g/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
认识defaultdict:
from collections import defaultdict
当我使用普通的字典时,用法一般是dict={},添加元素的只需要dict[element] =value即,调用的时候也是如此,dict[element] = xxx,但前提是element字典里,如果不在字典里就会报错,如:
这时defaultdict就能排上用场了,defaultdict的作用是在于,当字典里的key不存在但被查找时,返回的不是keyError而是一个默认值。
defaultdict接受一个工厂函数作为参数
dict =defaultdict( factory_function)
这个factory_function可以是list、set、str等等,作用是当key不存在时,返回的是工厂函数的默认值,比如list对应[ ],str对应的是空字符串,set对应set( ),int对应0。
注意:在这里使用了defaultdict,以及它的remove方法。
这个做法就是先将题目中的条件转为邻接矩阵,然后根据出度入队,然后在队列中和邻接矩阵中将遍历过的点进行删除,接着遍历当剩余未遍历的元素等于当前队列的元素,或者剩下的元素只有1-2个时返回结果,这其中deque()类型的结果需要转换成list。
class Solution: def findMinHeightTrees(self, n: int, edges: List[List[int]]) -> List[int]: neighbors=defaultdict(list) queue=collections.deque() visit=[0]*n if n==1: return [0] for item in edges: neighbors[item[0]].append(item[1]) neighbors[item[1]].append(item[0]) for key,value in neighbors.items(): if len(value)==1: queue.append(key) visit[key]=1 while queue: size=len(queue) if n==len(queue): return list(queue) for _ in range(size): item=queue.popleft() n-=1 nei=neighbors[item].pop() neighbors[nei].remove(item) if len(neighbors[nei])==1 and visit[nei]!=1: queue.append(nei) visit[nei]=1
递归方法,每次在一个点的邻接点中递归,通过记忆化减少时间复杂度,然后判断长度大小,将答案放入。
class Solution: def findMinHeightTrees(self, n: int, edges: List[List[int]]) -> List[int]: neighbors=defaultdict(list) memo=defaultdict(list) visit=[0]*n ans=[] for item in edges: neighbors[item[0]].append(item[1]) neighbors[item[1]].append(item[0]) def dfs(start,visit,root): key=start*1e5+root if key in memo: return memo[key] visit[start]=1 ret=0 for i in neighbors[start]: if visit[i]==1: continue ret=max(ret,dfs(i,visit,start)) memo[key]=ret+1 return ret+1 minvalue=float('inf') for i in range(n): visit=[0]*n depth=dfs(i,visit,-1)-1 print(depth) if depth<minvalue: ans.clear() ans.append(i) minvalue=depth elif depth==minvalue: ans.append(i) return ans
动态规划想法