diff --git a/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/README.md b/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/README.md index 63f9c8e3b38b4..21da7aa34b76f 100644 --- a/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/README.md +++ b/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/README.md @@ -62,47 +62,43 @@ ## 解法 -### 方法一 +### 方法一:贪心 + +根据题目描述,我们需要计算最小的增加次数,使得根节点到每个叶子节点的路径值相等。 + +根节点到每个叶子节点的路径值相等,实际上等价于以任意节点为根节点的子树到该子树的每个叶子节点的路径值相等。 + +为什么呢?我们可以用反证法来证明。假设存在一个节点 $x$,以它为根节点的子树到某个叶子节点的路径值不相等,那么也就存在着根节点到叶子节点的路径值不相等的情况,这与“根节点到每个叶子节点的路径值相等”矛盾。因此假设不成立,以任意节点为根节点的子树到该子树的每个叶子节点的路径值相等。 + +我们可以从树的底部开始,逐层向上计算增加次数。对于每个非叶子节点,我们可以计算它的左右孩子节点的路径值,增加的次数为两者路径值的差值,然后将左右孩子节点的路径值更新为两者中的较大值。 + +最后返回总的增加的次数即可。 + +时间复杂度 $O(n)$,其中 $n$ 为节点数。空间复杂度 $O(1)$。 ```python class Solution: def minIncrements(self, n: int, cost: List[int]) -> int: - def dfs(i: int) -> int: - if (i << 1) > n: - return cost[i - 1] - l, r = dfs(i << 1), dfs(i << 1 | 1) - nonlocal ans - ans += max(l, r) - min(l, r) - return cost[i - 1] + max(l, r) - ans = 0 - dfs(1) + for i in range(n >> 1, 0, -1): + l, r = i << 1, i << 1 | 1 + ans += abs(cost[l - 1] - cost[r - 1]) + cost[i - 1] += max(cost[l - 1], cost[r - 1]) return ans ``` ```java class Solution { - private int[] cost; - private int n; - private int ans; - public int minIncrements(int n, int[] cost) { - this.n = n; - this.cost = cost; - dfs(1); - return ans; - } - - private int dfs(int i) { - if ((i << 1) > n) { - return cost[i - 1]; + int ans = 0; + for (int i = n >> 1; i > 0; --i) { + int l = i << 1, r = i << 1 | 1; + ans += Math.abs(cost[l - 1] - cost[r - 1]); + cost[i - 1] += Math.max(cost[l - 1], cost[r - 1]); } - int l = dfs(i << 1); - int r = dfs(i << 1 | 1); - ans += Math.max(l, r) - Math.min(l, r); - return cost[i - 1] + Math.max(l, r); + return ans; } } ``` @@ -112,16 +108,11 @@ class Solution { public: int minIncrements(int n, vector& cost) { int ans = 0; - function dfs = [&](int i) -> int { - if ((i << 1) > n) { - return cost[i - 1]; - } - int l = dfs(i << 1); - int r = dfs(i << 1 | 1); - ans += max(l, r) - min(l, r); - return cost[i - 1] + max(l, r); - }; - dfs(1); + for (int i = n >> 1; i > 0; --i) { + int l = i << 1, r = i << 1 | 1; + ans += abs(cost[l - 1] - cost[r - 1]); + cost[i - 1] += max(cost[l - 1], cost[r - 1]); + } return ans; } }; @@ -129,32 +120,30 @@ public: ```go func minIncrements(n int, cost []int) (ans int) { - var dfs func(int) int - dfs = func(i int) int { - if (i << 1) > n { - return cost[i-1] - } - l, r := dfs(i<<1), dfs(i<<1|1) - ans += max(l, r) - min(l, r) - return cost[i-1] + max(l, r) + for i := n >> 1; i > 0; i-- { + l, r := i<<1, i<<1|1 + ans += abs(cost[l-1] - cost[r-1]) + cost[i-1] += max(cost[l-1], cost[r-1]) } - dfs(1) - return ans + return +} + +func abs(x int) int { + if x < 0 { + return -x + } + return x } ``` ```ts function minIncrements(n: number, cost: number[]): number { let ans = 0; - const dfs = (i: number): number => { - if (i << 1 > n) { - return cost[i - 1]; - } - const [a, b] = [dfs(i << 1), dfs((i << 1) | 1)]; - ans += Math.max(a, b) - Math.min(a, b); - return cost[i - 1] + Math.max(a, b); - }; - dfs(1); + for (let i = n >> 1; i; --i) { + const [l, r] = [i << 1, (i << 1) | 1]; + ans += Math.abs(cost[l - 1] - cost[r - 1]); + cost[i - 1] += Math.max(cost[l - 1], cost[r - 1]); + } return ans; } ``` diff --git a/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/README_EN.md b/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/README_EN.md index 8b007a2edb9e8..a0164c85857bf 100644 --- a/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/README_EN.md +++ b/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/README_EN.md @@ -54,47 +54,43 @@ It can be shown that this is the minimum answer we can achieve. ## Solutions -### Solution 1 +### Solution 1: Greedy Algorithm + +According to the problem description, we need to calculate the minimum number of increments to make the path values from the root node to each leaf node equal. + +The path values from the root node to each leaf node being equal is actually equivalent to the path values from any node as the root of a subtree to each leaf node of that subtree being equal. + +Why is that? We can prove it by contradiction. Suppose there is a node $x$, and the path values from it as the root of a subtree to some leaf nodes are not equal. Then there exists a situation where the path values from the root node to the leaf nodes are not equal, which contradicts the condition "the path values from the root node to each leaf node are equal". Therefore, the assumption is not valid, and the path values from any node as the root of a subtree to each leaf node of that subtree are equal. + +We can start from the bottom of the tree and calculate the number of increments layer by layer. For each non-leaf node, we can calculate the path values of its left and right child nodes. The number of increments is the difference between the two path values, and then update the path values of the left and right child nodes to the larger one of the two. + +Finally, return the total number of increments. + +The time complexity is $O(n)$, where $n$ is the number of nodes. The space complexity is $O(1)$. ```python class Solution: def minIncrements(self, n: int, cost: List[int]) -> int: - def dfs(i: int) -> int: - if (i << 1) > n: - return cost[i - 1] - l, r = dfs(i << 1), dfs(i << 1 | 1) - nonlocal ans - ans += max(l, r) - min(l, r) - return cost[i - 1] + max(l, r) - ans = 0 - dfs(1) + for i in range(n >> 1, 0, -1): + l, r = i << 1, i << 1 | 1 + ans += abs(cost[l - 1] - cost[r - 1]) + cost[i - 1] += max(cost[l - 1], cost[r - 1]) return ans ``` ```java class Solution { - private int[] cost; - private int n; - private int ans; - public int minIncrements(int n, int[] cost) { - this.n = n; - this.cost = cost; - dfs(1); - return ans; - } - - private int dfs(int i) { - if ((i << 1) > n) { - return cost[i - 1]; + int ans = 0; + for (int i = n >> 1; i > 0; --i) { + int l = i << 1, r = i << 1 | 1; + ans += Math.abs(cost[l - 1] - cost[r - 1]); + cost[i - 1] += Math.max(cost[l - 1], cost[r - 1]); } - int l = dfs(i << 1); - int r = dfs(i << 1 | 1); - ans += Math.max(l, r) - Math.min(l, r); - return cost[i - 1] + Math.max(l, r); + return ans; } } ``` @@ -104,16 +100,11 @@ class Solution { public: int minIncrements(int n, vector& cost) { int ans = 0; - function dfs = [&](int i) -> int { - if ((i << 1) > n) { - return cost[i - 1]; - } - int l = dfs(i << 1); - int r = dfs(i << 1 | 1); - ans += max(l, r) - min(l, r); - return cost[i - 1] + max(l, r); - }; - dfs(1); + for (int i = n >> 1; i > 0; --i) { + int l = i << 1, r = i << 1 | 1; + ans += abs(cost[l - 1] - cost[r - 1]); + cost[i - 1] += max(cost[l - 1], cost[r - 1]); + } return ans; } }; @@ -121,32 +112,30 @@ public: ```go func minIncrements(n int, cost []int) (ans int) { - var dfs func(int) int - dfs = func(i int) int { - if (i << 1) > n { - return cost[i-1] - } - l, r := dfs(i<<1), dfs(i<<1|1) - ans += max(l, r) - min(l, r) - return cost[i-1] + max(l, r) + for i := n >> 1; i > 0; i-- { + l, r := i<<1, i<<1|1 + ans += abs(cost[l-1] - cost[r-1]) + cost[i-1] += max(cost[l-1], cost[r-1]) } - dfs(1) - return ans + return +} + +func abs(x int) int { + if x < 0 { + return -x + } + return x } ``` ```ts function minIncrements(n: number, cost: number[]): number { let ans = 0; - const dfs = (i: number): number => { - if (i << 1 > n) { - return cost[i - 1]; - } - const [a, b] = [dfs(i << 1), dfs((i << 1) | 1)]; - ans += Math.max(a, b) - Math.min(a, b); - return cost[i - 1] + Math.max(a, b); - }; - dfs(1); + for (let i = n >> 1; i; --i) { + const [l, r] = [i << 1, (i << 1) | 1]; + ans += Math.abs(cost[l - 1] - cost[r - 1]); + cost[i - 1] += Math.max(cost[l - 1], cost[r - 1]); + } return ans; } ``` diff --git a/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.cpp b/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.cpp index c6282c6923263..afca58738ba62 100644 --- a/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.cpp +++ b/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.cpp @@ -2,16 +2,11 @@ class Solution { public: int minIncrements(int n, vector& cost) { int ans = 0; - function dfs = [&](int i) -> int { - if ((i << 1) > n) { - return cost[i - 1]; - } - int l = dfs(i << 1); - int r = dfs(i << 1 | 1); - ans += max(l, r) - min(l, r); - return cost[i - 1] + max(l, r); - }; - dfs(1); + for (int i = n >> 1; i > 0; --i) { + int l = i << 1, r = i << 1 | 1; + ans += abs(cost[l - 1] - cost[r - 1]); + cost[i - 1] += max(cost[l - 1], cost[r - 1]); + } return ans; } }; \ No newline at end of file diff --git a/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.go b/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.go index 8e0d6c4272f2e..2373df255b5d6 100644 --- a/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.go +++ b/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.go @@ -1,13 +1,15 @@ func minIncrements(n int, cost []int) (ans int) { - var dfs func(int) int - dfs = func(i int) int { - if (i << 1) > n { - return cost[i-1] - } - l, r := dfs(i<<1), dfs(i<<1|1) - ans += max(l, r) - min(l, r) - return cost[i-1] + max(l, r) + for i := n >> 1; i > 0; i-- { + l, r := i<<1, i<<1|1 + ans += abs(cost[l-1] - cost[r-1]) + cost[i-1] += max(cost[l-1], cost[r-1]) } - dfs(1) - return ans + return +} + +func abs(x int) int { + if x < 0 { + return -x + } + return x } \ No newline at end of file diff --git a/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.java b/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.java index ba3df40754c49..9e08bfb1998b7 100644 --- a/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.java +++ b/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.java @@ -1,22 +1,11 @@ class Solution { - private int[] cost; - private int n; - private int ans; - public int minIncrements(int n, int[] cost) { - this.n = n; - this.cost = cost; - dfs(1); - return ans; - } - - private int dfs(int i) { - if ((i << 1) > n) { - return cost[i - 1]; + int ans = 0; + for (int i = n >> 1; i > 0; --i) { + int l = i << 1, r = i << 1 | 1; + ans += Math.abs(cost[l - 1] - cost[r - 1]); + cost[i - 1] += Math.max(cost[l - 1], cost[r - 1]); } - int l = dfs(i << 1); - int r = dfs(i << 1 | 1); - ans += Math.max(l, r) - Math.min(l, r); - return cost[i - 1] + Math.max(l, r); + return ans; } } \ No newline at end of file diff --git a/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.py b/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.py index fe1cfc3a7ed18..9671e3e13de87 100644 --- a/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.py +++ b/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.py @@ -1,13 +1,8 @@ class Solution: def minIncrements(self, n: int, cost: List[int]) -> int: - def dfs(i: int) -> int: - if (i << 1) > n: - return cost[i - 1] - l, r = dfs(i << 1), dfs(i << 1 | 1) - nonlocal ans - ans += max(l, r) - min(l, r) - return cost[i - 1] + max(l, r) - ans = 0 - dfs(1) + for i in range(n >> 1, 0, -1): + l, r = i << 1, i << 1 | 1 + ans += abs(cost[l - 1] - cost[r - 1]) + cost[i - 1] += max(cost[l - 1], cost[r - 1]) return ans diff --git a/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.ts b/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.ts index 9511a55f6ef72..3dc20194d9ede 100644 --- a/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.ts +++ b/solution/2600-2699/2673.Make Costs of Paths Equal in a Binary Tree/Solution.ts @@ -1,13 +1,9 @@ function minIncrements(n: number, cost: number[]): number { let ans = 0; - const dfs = (i: number): number => { - if (i << 1 > n) { - return cost[i - 1]; - } - const [a, b] = [dfs(i << 1), dfs((i << 1) | 1)]; - ans += Math.max(a, b) - Math.min(a, b); - return cost[i - 1] + Math.max(a, b); - }; - dfs(1); + for (let i = n >> 1; i; --i) { + const [l, r] = [i << 1, (i << 1) | 1]; + ans += Math.abs(cost[l - 1] - cost[r - 1]); + cost[i - 1] += Math.max(cost[l - 1], cost[r - 1]); + } return ans; }