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的路徑斷開,得到下圖。
記: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在整個樹的路徑和是:
。
編碼過程:
1 answer[]儲存以每個節點為根節點在整個樹的路徑和;
2 count[] 儲存以每個節點為根節點的子樹的節點數,初始化每個元素值=1;
3 對某個節點node,dfs後序遍歷,先處理子節點,計算每個子節點y的count和stsum,
,
,當遍歷了所有的邊以後
;如果我們從節點0開始遍歷。這次遍歷結束後只有answer[0]是正確的。其他節點都沒有遍歷完全。
4 再看,上面分析了兩個相鄰節點(父子節點)的路徑和關係。如果有節點parent和子節點child,則有
,因為我們已經得到answer[0]的正確結果,可以依據算式計算節點0的子節點的answer。算式中之所以使用count[child]來計算count[parent]:
,是因為在上一步的後續遍歷過程中,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。
程式碼