題意
給出一棵二叉樹,樹的每個節點上都有指定數量的金幣。現在問,通過把金幣從相鄰節點間傳遞,每次只能移動一枚硬幣,最少需要移動多少次,能夠使得每個非空節點有且只有一枚硬幣?
解法
我們定義函數dfs(x)表示節點x給父節點的金幣個數:正數代表子節點給父節點,負數代表子節點從父節點要過來金幣。那麼這個題就是求 全部非根結點需要移動次數的絕對值之和。即sum(abs(dfs(非根結點)))。下面用例子講解:
看上面這個例子,
dfs(左孩子)= -1:表示左孩子要從父節點那要過來1個。
dfs(右孩子)=-1:同理。
所以總移動次數=abs(dfs(左孩子))+abs(dfs(右孩子))=2。注意:我們要對孩子節點的dfs值取絕對值的。因爲送給父節點還是要過來都是要那麼多操作次數的
再看個例子,如上圖,dfs(左孩子)= 2,dfs(右孩子)=-1。總移動次數=dfs(左孩子)+abs(dfs(右孩子))=2+1=3。
所以這個題就是求 全部非根結點需要移動的次數的絕對值之和。爲啥是非根呢?因爲如果子節點都是1了,根結點肯定是1了嘛。
代碼實現
我們還是看個例子:
如上圖,我們從下往上考慮每個小子樹。首先考慮左下角的那個0:
- 他沒有左子樹,那麼他的左子樹不需要移動硬幣。即dfs(l) = 0;
- 他的右子樹有三個節點,那麼需要移動兩次來達到1,因爲他自己需要留一個嘛。即dfs( r) = 2
- 那現在左下角這個0有2個硬幣了,他需要移動的硬幣數=左孩子給他的+右孩子給他的+他自己的-1。
- 其他以此類推。
注意這個dfs(x)並不是我們要的結果,我們要的結果是非節點的移動次數絕對值。所以上代碼。
python代碼
class Solution(object):
def distributeCoins(self, root):
self.ans = 0
def dfs(node):
if not node: return 0
L, R = dfs(node.left), dfs(node.right)
self.ans += abs(L) + abs(R)
return node.val + L + R - 1
dfs(root)
return self.ans
java代碼
class Solution {
int ans;
public int distributeCoins(TreeNode root) {
ans = 0;
dfs(root);
return ans;
}
public int dfs(TreeNode node) {
if (node == null) return 0;
int L = dfs(node.left);
int R = dfs(node.right);
ans += Math.abs(L) + Math.abs(R);
return node.val + L + R - 1;
}
}