leetcode
leetcode 1451 ~ 1500
无矛盾的最佳球队

无矛盾的最佳球队

难度:

标签:

题目描述

代码结果

运行时间: 100 ms, 内存: 16.3 MB


/*
 * 思路:
 * 1. 将球员按年龄和分数排序,以便处理无矛盾的选择。
 * 2. 使用动态规划(DP)方法来计算最佳得分。
 * 3. dp[i] 表示选择第 i 名球员时的最佳得分。
 * 4. 对于每个球员 i,检查之前的每个球员 j,如果没有矛盾,则更新 dp[i]。
 */
import java.util.Arrays;
import java.util.stream.IntStream;

public class BestTeamScoreStream {
    public int bestTeamScore(int[] scores, int[] ages) {
        int n = scores.length;
        int[][] players = IntStream.range(0, n)
                                    .mapToObj(i -> new int[]{ages[i], scores[i]})
                                    .sorted((a, b) -> (a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]))
                                    .toArray(int[][]::new);
        int[] dp = new int[n];
        int maxScore = 0;
        for (int i = 0; i < n; i++) {
            dp[i] = players[i][1];
            for (int j = 0; j < i; j++) {
                if (players[j][1] <= players[i][1]) {
                    dp[i] = Math.max(dp[i], dp[j] + players[i][1]);
                }
            }
            maxScore = Math.max(maxScore, dp[i]);
        }
        return maxScore;
    }

    public static void main(String[] args) {
        BestTeamScoreStream bts = new BestTeamScoreStream();
        int[] scores1 = {1, 3, 5, 10, 15};
        int[] ages1 = {1, 2, 3, 4, 5};
        System.out.println(bts.bestTeamScore(scores1, ages1)); // 输出:34

        int[] scores2 = {4, 5, 6, 5};
        int[] ages2 = {2, 1, 2, 1};
        System.out.println(bts.bestTeamScore(scores2, ages2)); // 输出:16

        int[] scores3 = {1, 2, 3, 5};
        int[] ages3 = {8, 9, 10, 1};
        System.out.println(bts.bestTeamScore(scores3, ages3)); // 输出:6
    }
}

解释

方法:

本题解采用了结合排序和树状数组(Binary Indexed Tree, BIT)的动态规划方法。首先,通过将球员按照年龄排序(如果年龄相同则按分数排序),确保能够以非降序处理球员。这样,在处理每个球员时,可以保证其之前的球员要么年龄小于等于当前球员,要么年龄相同但分数不大于当前球员。然后,使用树状数组来维护不同年龄下可达到的最高分数总和。对于每个球员,通过树状数组查询当前年龄可达到的最大分数,并更新该年龄的分数总和。最后,通过查询最大年龄的信息,得到最大分数总和。

时间复杂度:

O(n log n + n log(maxAge))

空间复杂度:

O(maxAge + n)

代码细节讲解

🦆
在题解中,为什么首先需要将球员按照年龄和分数进行排序?排序的具体规则是什么,即当年龄相同时分数如何排序?
球员的排序是为了保证处理球员时,可以通过动态规划的方式逐步构建最佳球队。排序规则是首先按年龄升序排序,如果年龄相同,则按分数升序排序。这样做的目的是在处理每个球员时,可以保证之前处理的球员要么年龄小于等于当前球员,要么年龄相同但分数不大于当前球员。这种排序方式确保了在使用动态规划时,可以正确地依赖之前的状态来更新当前状态,从而找到最优解。
🦆
题解中提到使用树状数组(Binary Indexed Tree, BIT)来维护最高分数总和,树状数组中每个位置代表的具体含义是什么?
在这个题解中,树状数组中的每个位置代表了对应年龄的最高分数总和。具体来说,如果树状数组的索引为i,则该位置存储的是年龄为i的球员组成的球队可以达到的最高分数总和。这种结构允许我们通过高效的更新和查询操作,快速地计算和更新不同年龄下的球队的最高分数总和。
🦆
在使用树状数组的查询和更新操作中,查询函数`query()`的实现逻辑是什么,它如何确保能获取到当前年龄最大的分数总和?
查询函数`query()`的实现逻辑是从指定的年龄开始,向下迭代到年龄1,通过树状数组中的链接结构逐个查询更小的年龄范围,累计这些范围内的最大分数总和。在每次迭代中,它使用`i &= i - 1`来移动到下一个需要查询的索引。这种方法确保了能够获取到从年龄1到当前年龄i的球员组成的球队可能达到的最大分数总和。
🦆
更新函数`update()`在树状数组中的作用是什么,它是如何确保树状数组中存储的是某个年龄下的最高分数总和的?
更新函数`update()`的作用是将树状数组中的某个特定年龄的最高分数总和更新为新的更高值。它通过从指定的年龄索引开始,逐步向数组的较高索引移动,并在每个步骤中更新存储的分数总和。这是通过`i += i & -i`实现的,该操作确保了能逐步覆盖所有包含该年龄的范围。这种更新保证了在任何给定的年龄点,树状数组都能反映出到目前为止可能组成的最佳球队的最高分数总和。

相关问题