leetcode
leetcode 2201 ~ 2250
最大价值和与最小价值和的差值

最大价值和与最小价值和的差值

难度:

标签:

题目描述

There exists an undirected and initially unrooted tree with n nodes indexed from 0 to n - 1. You are given the integer n and a 2D integer array edges of length n - 1, where edges[i] = [ai, bi] indicates that there is an edge between nodes ai and bi in the tree.

Each node has an associated price. You are given an integer array price, where price[i] is the price of the ith node.

The price sum of a given path is the sum of the prices of all nodes lying on that path.

The tree can be rooted at any node root of your choice. The incurred cost after choosing root is the difference between the maximum and minimum price sum amongst all paths starting at root.

Return the maximum possible cost amongst all possible root choices.

 

Example 1:

Input: n = 6, edges = [[0,1],[1,2],[1,3],[3,4],[3,5]], price = [9,8,7,6,10,5]
Output: 24
Explanation: The diagram above denotes the tree after rooting it at node 2. The first part (colored in red) shows the path with the maximum price sum. The second part (colored in blue) shows the path with the minimum price sum.
- The first path contains nodes [2,1,3,4]: the prices are [7,8,6,10], and the sum of the prices is 31.
- The second path contains the node [2] with the price [7].
The difference between the maximum and minimum price sum is 24. It can be proved that 24 is the maximum cost.

Example 2:

Input: n = 3, edges = [[0,1],[1,2]], price = [1,1,1]
Output: 2
Explanation: The diagram above denotes the tree after rooting it at node 0. The first part (colored in red) shows the path with the maximum price sum. The second part (colored in blue) shows the path with the minimum price sum.
- The first path contains nodes [0,1,2]: the prices are [1,1,1], and the sum of the prices is 3.
- The second path contains node [0] with a price [1].
The difference between the maximum and minimum price sum is 2. It can be proved that 2 is the maximum cost.

 

Constraints:

  • 1 <= n <= 105
  • edges.length == n - 1
  • 0 <= ai, bi <= n - 1
  • edges represents a valid tree.
  • price.length == n
  • 1 <= price[i] <= 105

代码结果

运行时间: 296 ms, 内存: 49.1 MB


/*
题目思路:
1. 使用Java Stream API来处理节点及边的数据。
2. 使用递归函数与Stream结合计算每个节点作为根的最大路径和和最小路径和。
3. 使用Stream计算并获取所有可能根节点中的最大差值。
*/

import java.util.*;
import java.util.stream.*;

public class Solution {
    private int[] prices;
    private List<Integer>[] tree;

    public int maxCost(int n, int[][] edges, int[] price) {
        this.prices = price;
        this.tree = Stream.generate(ArrayList<Integer>::new).limit(n).toArray(ArrayList[]::new);
        Arrays.stream(edges).forEach(edge -> {
            tree[edge[0]].add(edge[1]);
            tree[edge[1]].add(edge[0]);
        });
        return IntStream.range(0, n)
            .map(i -> {
                boolean[] visited = new boolean[n];
                int[] maxMin = dfs(i, visited);
                return maxMin[0] - maxMin[1];
            })
            .max().orElse(0);
    }

    private int[] dfs(int root, boolean[] visited) {
        visited[root] = true;
        int maxSum = prices[root];
        int minSum = prices[root];
        for (int neighbor : tree[root]) {
            if (!visited[neighbor]) {
                int[] childMaxMin = dfs(neighbor, visited);
                maxSum = Math.max(maxSum, prices[root] + childMaxMin[0]);
                minSum = Math.min(minSum, childMaxMin[1]);
            }
        }
        return new int[] { maxSum, minSum };
    }
}

解释

方法:

此题解使用深度优先搜索(DFS)来计算以每个节点为根时的最大开销。首先,构建图的邻接表表示。然后,从任意节点(如节点0)开始进行DFS遍历。在遍历过程中,对于每一个节点x,计算以x为根节点的两种路径和:最大价值和(max_s1)和次大价值和(max_s2)。对于x的每一个孩子节点y,递归地计算以y为根的最大和次大路径和,并更新当前节点x的max_s1和max_s2。同时,在每次递归调用中,计算并更新全局最大开销res,确保记录下在所有可能的根选择中,最大路径和与最小路径和的最大差值。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在计算最大和次大路径和时,您是如何确保不会重复统计节点的价值,特别是在处理树的分支时?
在DFS过程中,每次从一个节点x向它的孩子节点y进行递归调用时,我们传递了当前节点x作为参数fa(父节点)。在节点y的DFS执行中,我们会检查每个邻接点是否为fa,如果是,就跳过这个邻接点,从而避免回到父节点x,这样就确保了每个节点的价值只被计算一次,避免了重复统计。同时,这种方法也确保了每个节点只与其子节点(而非父节点或已访问的兄弟节点)的路径和进行合并,确保了路径和的计算只在树的分支间进行,没有重复。
🦆
代码中提到了全局变量res用于记录最大开销,但在dfs函数中更新res的逻辑是否能够保证始终捕捉到全局最大的差值?能否详细解释其更新条件`res = max(res, max_s1 + s2, max_s2 + s1)`的含义?
在DFS函数中,每个节点x计算得到两个值:max_s1(以x为根的最大路径和)和max_s2(以x为根的次大路径和)。对于x的每个孩子节点y,我们通过递归得到y的最大和次大路径和s1与s2。更新全局变量res的逻辑`res = max(res, max_s1 + s2, max_s2 + s1)`意味着我们不仅考虑了从当前节点x通过其某个孩子y回到x的两个最大可能路径和的组合(即x到y的最大路径和与其他孩子的次大路径和之和),还考虑了将这些路径和与其它可能的路径组合进行比较,从而更新全局最大的差值。这确保我们能够在所有可能的路径组合中找到最大的和差值。
🦆
您提到使用深度优先搜索(DFS)进行遍历,但在树极度不平衡的情况下,递归调用栈的深度可能会非常深。这种情况下是否有可能导致栈溢出?如果有,如何改进算法以避免这种情况?
是的,如果树极度不平衡,比如形成一个长链,DFS的递归调用栈可能非常深,从而引发栈溢出。为了解决这个问题,可以采用迭代的深度优先搜索(使用显式栈)或广度优先搜索(BFS)来代替递归的DFS。这样可以手动控制栈的使用,避免因递归过深而导致的栈溢出问题。另一种方法是使用尾递归优化,尽管这依赖于编程语言的编译器是否支持尾调用优化。

相关问题