1. 程式人生 > >Depth-first Search深度優先搜尋專題7

Depth-first Search深度優先搜尋專題7

834 Sum of Distances in Tree

思路:一顆無向的樹有N個節點,分別標記為0,1,2,…N-1,有若干條邊。結果返回每個節點到其他節點的路徑和。
這裡寫圖片描述
以上面這棵樹為例。從節點0到其他點的路徑查詢過程是:節點0有兩條邊分別到達子節點1和子節點2;遞迴查詢節點1(節點1沒有子節點),節點2;繼續查詢節點2的子節點…依次下去。遞迴每進一層,路徑就需要加1。
遍歷完節點0以後,再以節點1為根節點,遍歷。
時間複雜度O(N*E),E是邊的數目。這個思路超時。既然是超時,定是因為有重複計算的。例如遍歷邊(0,2),之後又遍歷了一次(2,0)。但是該怎麼合併計算,我沒想出來。
學習:接下來的描述,相當於翻譯

官方解釋吧。
這裡寫圖片描述
用一顆新的樹為例子。節點0和節點4是父子關係,也是相鄰節點。現在觀察一下相鄰節點連線後,路徑和發生什麼變化。
將節點0和節點4的路徑斷開,得到下圖。
節點0的子樹 節點4的子樹
記:stsum[0] 表示節點0在節點0子樹上的路徑和。stsum[4]表示節點4在節點4子樹上的路徑和。count[0]表示節點0子樹的節點數。answer[0]表示節點0在整個樹的路徑和。answer[4]表示節點4在整個樹的路徑和。

當節點0和節點4之間加上路徑後,answer[0]= stsum[0] + stsum[4] + count[4]。因為節點0到節點4子樹上所有點的距離與節點4到節點4子樹上所有點的距離都要加1。answer[4]= stsum[4] + stsum[0] + count[0]。而且能得到answer[0]-answer[4]=count[4]-count[0]。

所以得到結論:相鄰節點(父子節點)x,y在整個樹的路徑和是: a n s w e r [ x ]

a n s w e r [ y ] = c o u n t [ y ] c o u n t [ x ] answer[x] -answer[y] = count[y] - count[x]
編碼過程:
1 answer[]儲存以每個節點為根節點在整個樹的路徑和;
2 count[] 儲存以每個節點為根節點的子樹的節點數,初始化每個元素值=1;
3 對某個節點node,dfs後序遍歷,先處理子節點,計算每個子節點y的count和stsum, c o u n t [ n o d e ] + = c o u n t [ c h i l d ] count[node]+=count[child] s t s u m [ n o d e ] + = s t s u m [ c h i l d ] + c o u n t [ c h i l d ] stsum[node] +=stsum[child]+count[child] ,當遍歷了所有的邊以後 a n s w e r [ n o d e ] = s t s u m [ n o d e ] answer[node] = stsum[node] ;如果我們從節點0開始遍歷。這次遍歷結束後只有answer[0]是正確的。其他節點都沒有遍歷完全。
4 再看,上面分析了兩個相鄰節點(父子節點)的路徑和關係。如果有節點parent和子節點child,則有 a n s w e r [ c h i l d ] = a n s w e r [ p a r e n t ] c o u n t [ c h i l d ] + ( N c o u n t [ c h i l d ] ) answer[child] = answer[parent] - count[child] + (N - count[child]) ,因為我們已經得到answer[0]的正確結果,可以依據算式計算節點0的子節點的answer。算式中之所以使用count[child]來計算count[parent]: N c o u n t [ c h i l d ] ) = c o u n t [ p r e n t ] N - count[child])=count[prent] ,是因為在上一步的後續遍歷過程中,count[parent]的值已經發生變化,不再是parent、child狀態下的count
(原文的解釋是:count[child]從child得到parent比較容易)。用先序遍歷再次遍歷樹,修改每個子節點的answer,得到最終結果。
程式碼

301 Remove Invalid Parentheses

思路:最直接的想法:把s中每一個(,)去掉,檢查新的字串是不是有效字串,如果是則加入到結果集。
這樣不符合題意的要求:去掉最少的括號。那麼需要計算最少去掉幾個左括號,去掉幾個右括號,就可以是有效字串。
在編碼過程中注意去重。
程式碼
學習:可以改進,不再需要判斷是否是有效字串。新增變數open。有效字元的特徵是:左括號在前,所以open>0;左右括號個數相同=>open=0;多餘的左右括號都去掉了=>leftCount=0 and rightCount=0。
程式碼