算法分析与设计第三周习题:图论算法之310. Minimum Height Trees
2017-03-09 22:27
447 查看
今天刚上完算法课,课上知识内容包括拓扑排序和图论一些基本知识,所以我就去leetcode上面找了一道有关图论的题目来巩固自己所学的知识。
题目简介:
For a undirected graph with tree characteristics, we can choose any node as the root. The result graph is then a rooted tree. Among all possible rooted trees, those with minimum height are called minimum height trees (MHTs). Given such a graph, write a function to find all the MHTs and return a list of their root labels.
Format
The graph contains n nodes which are labeled from 0 to n - 1. You will be given the number n and a list of undirected edges (each edge is a pair of labels).
You can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges.
提炼内容:
从一个无向图中寻找一个根节点,使得该根节点生成的树拥有最小的高度。
显然,如果对每个节点使用DFS或者BFS去搜索该节点的树高度将会得到
O(V(V+E))的时间,这是一个十分慢的搜索过程。
因此,我试着换个角度来思考这个问题。如果一条根到叶子的路径上包含a,b,c,d,e,f,g七个点,那么当我们选取中间点d作为根时,d到所有节点的路径是最短的(相比b到g或者a到f)。也就是说,我们可以从图中逐个删除度为1的节点,那么当图中最后只剩一条边或者无边的时候,即可获得中间节点,也就是生成树高度最小的根节点。
第一次尝试:
不使用邻接表保存边,不使用列表保存度为1的叶子节点后所产生的新节点。测试结果,只通过62个测例,当节点数达到2020时,算法超时。
第二次尝试:
使用列表保存新叶子,当测例节点数达到5000时超时。
第三次尝试:
参考了leetcode上其他用户所使用的数据结构,改用邻接表保存边(而不是每次都遍历edges)且使用列表保存新叶子。AC
至此,该题代码编写完毕。累。。。
题目简介:
For a undirected graph with tree characteristics, we can choose any node as the root. The result graph is then a rooted tree. Among all possible rooted trees, those with minimum height are called minimum height trees (MHTs). Given such a graph, write a function to find all the MHTs and return a list of their root labels.
Format
The graph contains n nodes which are labeled from 0 to n - 1. You will be given the number n and a list of undirected edges (each edge is a pair of labels).
You can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges.
提炼内容:
从一个无向图中寻找一个根节点,使得该根节点生成的树拥有最小的高度。
显然,如果对每个节点使用DFS或者BFS去搜索该节点的树高度将会得到
O(V(V+E))的时间,这是一个十分慢的搜索过程。
因此,我试着换个角度来思考这个问题。如果一条根到叶子的路径上包含a,b,c,d,e,f,g七个点,那么当我们选取中间点d作为根时,d到所有节点的路径是最短的(相比b到g或者a到f)。也就是说,我们可以从图中逐个删除度为1的节点,那么当图中最后只剩一条边或者无边的时候,即可获得中间节点,也就是生成树高度最小的根节点。
第一次尝试:
不使用邻接表保存边,不使用列表保存度为1的叶子节点后所产生的新节点。测试结果,只通过62个测例,当节点数达到2020时,算法超时。
#找度为1的点,根据其边来减小点的度数,然后删除该点 #重复该步骤直至无点度数大于1 while 1: hasDegreeMoreThan1 = False oneDegreeNodeList = [] for i in range(n): if degree[i][1] == False: if degree[i][0] == 1: oneDegreeNodeList.append(i) #只剩一个点的情况 elif degree[i][0] == 0: return [i] else: hasDegreeMoreThan1 = True if hasDegreeMoreThan1: #如果有度数大于1的点,则根据入度为1的点的边减少相应点的度数 for i in range(len(oneDegreeNodeList)): for j in range(len(edges)): #访问完毕便删除度数等于1的点的边 if edges[j][0] == oneDegreeNodeList[i]: degree[edges[j][1]][0] -= 1 del edges[j] break elif edges[j][1] == oneDegreeNodeList[i]: degree[edges[j][0]][0] -= 1 del edges[j] break #标记度数为1的点已被删除 degree[oneDegreeNodeList[i]][1] = True else: return oneDegreeNodeList
第二次尝试:
使用列表保存新叶子,当测例节点数达到5000时超时。
#重复该步骤直至无点度数大于1 while size - usedEdgeCounts > 1: #用来保存新的度数为1的点 newOneDegList = [] #如果有度数大于1的点,则根据入度为1的点的边减少相应点的度数 for i in range(len(oneDegreeNodeList)): for j in range(len(edges)): #访问完毕便删除度数等于1的点的边 if edges[j][0] == oneDegreeNodeList[i]: degree[edges[j][1]] -= 1 if degree[edges[j][1]] == 1: newOneDegList.append(edges[j][1]) #若有度数为0的点即可直接返回 elif degree[edges[j][1]] == 0: return [edges[j][1]] del edges[j] usedEdgeCounts += 1 break elif edges[j][1] == oneDegreeNodeList[i]: degree[edges[j][0]] -= 1 if degree[edges[j][0]] == 1: newOneDegList.append(edges[j][0]) elif degree[edges[j][0]] == 0: return [edges[j][0]] del edges[j] usedEdgeCounts += 1 break oneDegreeNodeList = newOneDegList return oneDegreeNodeList
第三次尝试:
参考了leetcode上其他用户所使用的数据结构,改用邻接表保存边(而不是每次都遍历edges)且使用列表保存新叶子。AC
#度为1的点必为叶子节点,若以度为1的点作为根,则生成树高度最高 #算法思想:从图中逐个删除入度为1的点,直至只剩下入度为1的点即为高度最小的根。 class Solution(object): def findMinHeightTrees(self, n, edges): #无顶点则直接返回空 if n == 0: return [] #无边则返回各个定点 if edges == []: return [x for x in range(n)] #统计边个数并用邻接表将边存储起来 size = len(edges) adjList = [set() for _ in range(n)] for i, j in edges: adjList[i].add(j) adjList[j].add(i) leaves = [] for i in range(len(adjList)): if len(adjList[i]) == 1: leaves.append(i) while size > 1: newLeaves = [] for leaf in leaves: node = adjList[leaf].pop() adjList[node].remove(leaf) if len(adjList[node]) == 1: newLeaves.append(node) elif len(adjList[node]) == 0: return [node] size -= len(leaves) leaves = newLeaves return leaves
至此,该题代码编写完毕。累。。。
相关文章推荐
- 第三周算法分析与设计:Search in Rotated Sorted Array
- 【算法分析与设计】【第三周】215. Kth Largest Element in an Array
- 算法分析与设计第五周习题:95. Unique Binary Search Trees II
- 算法分析与设计课程作业第三周#1
- 算法分析与设计第一周习题:2. Add Two Numbers
- 算法分析与设计丨第十七周丨算法概论第八章习题——k-spanning tree(8.12)
- Stanford公开课之算法:设计与分析——(第三周) Programming Question-3
- [算法分析与设计] leetcode 每周一题: 310. Minimum Height Trees
- 算法分析与设计第三周
- 算法分析与设计第二周习题:分治算法之P215,P169,P53
- 算法分析与设计基础
- 算法分析与设计之五大常用算法
- 算法分析与设计的作业:“基于FMM的分词系统”
- 【算法分析与设计】——八皇后问题的详解
- 动态规划法之投资问题_算法分析与设计
- YUV / RGB 格式分析及快速查表算法设计
- YUV / RGB 格式分析及快速查表算法设计
- 算法分析与设计课程总结
- 算法设计与分析课
- 算法设计与分析之递归与分治策略