拓撲排序變種題:Leetcode310最小高度樹
問題:
思路:
借用了BFS的思想,一次性將度爲1的節點全部刪除,不斷進行此操作,直至只剩2個或1個節點
正確性證明:
無向無環圖A在刪除度爲1的結點後得到無向無環圖B。可以證明,圖A所成最小高度樹TreeA是由圖B所成的最小高度樹TreeB接上被刪除結點後構成的。反證法:圖B所成的樹TreeB如果不是最小高度樹,那麼存在圖B的最小高度樹TreeB’,TreeB’的高度比TreeB更小。那麼TreeB’接上被刪除結點後高度比TreeA更小,這與TreeA是最小高度樹矛盾。
既然圖A的最小高度樹是由圖B的最小高度樹接上被刪除的結點所成。那麼圖A的最小高度樹的根結點與圖B的最小高度樹的根結點是相同的,因爲,接上被刪除的結點不會成爲根結點,否則相比不成爲根結點的高度還要高1。因此找圖A的最小高度樹的根結點演變爲找圖B的最小高度樹的根結點。
使用隊列,首先將度爲1的節點全部入隊,計算隊列長度
之後進入循環,循環的終止條件爲剩下的節點數<=2。
在循環中先將節點數減去隊列長度得到剩餘節點數,接下來每次將隊列中元素pop出,並將已pop出的元素的度賦爲0(該節點已被刪除),對於該元素鄰接表中的所有未被刪除的元素(度不爲0),將其度-1,若減1後度爲1,將其加入隊列
代碼:
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
vector<int> ans;
if( n==1 )
{
ans.push_back(0);
return ans;
}
if( n==2 )
{
ans.push_back(0);
ans.push_back(1);
return ans;
}
int* indegree;
indegree=(int*)malloc( n*sizeof(int) );
int i;
for( i=0;i<n;i++ )
indegree[i]=0;
for( i=0;i<edges.size();i++ )
{
indegree[ edges[i][0] ]++;
indegree[ edges[i][1] ]++;
}
vector<vector<int>> table;
for( i=0;i<n;i++ )
table.push_back( vector<int>() );
for( i=0;i<edges.size();i++ )
{
table[ edges[i][1] ].push_back( edges[i][0] );
table[ edges[i][0] ].push_back( edges[i][1] );
}
queue<int> queue;
for( i=0;i<n;i++ )
{
if( indegree[i]==1 )
{
queue.push(i);
}
}
int len=queue.size();
int vertex;
while( n>2 )
{
n-=len;
while( len-- )
{
vertex=queue.front();
queue.pop();
indegree[vertex]=0;
for( i=0;i<table[vertex].size();i++ )
{
if( indegree[ table[vertex][i] ]!=0 )
{
if( --indegree[ table[vertex][i] ]==1 )
queue.push( table[vertex][i] );
}
}
}
len=queue.size();
}
while( queue.size()!=0 )
{
vertex=queue.front();
queue.pop();
ans.push_back(vertex);
}
return ans;
}
};