Dynamic Programming学习笔记 (39) - 统计作战单位数 (力扣# 1395)

129 阅读1分钟

本题出自力扣题库第1395题。题面大意如下:

n名士兵站成一排。每个士兵都有一个独一无二 的评分rating 。 每 3 个士兵可以组成一个作战单位,分组规则如下: 从队伍中选出下标分别为 i、j、k 的 3 名士兵,他们的评分分别为 rating[i]、rating[j]、rating[k] 作战单位需满足: rating[i] < rating[j] < rating[k] 或者 rating[i] > rating[j] > rating[k] ,其中 0 <= i < j < k < n 返回按上述条件可以组建的作战单位数量。每个士兵都可以是多个作战单位的一部分。

示例:

输入:rating = [2,5,3,4,1]
输出:3
解释:可以组建三个作战单位 (2,3,4)、(5,4,1)、(5,3,1) 。

题解:

从题目要求出发,我们需要找到从给定的数组中找到有多少三个元素的组合满足从小到大,或是从大到小的要求,以从小到大排列为例,我们使用一个一维DP数组,其第j个元素的数值对应于rating数组中第i个元素之前有多少个元素比rating[j]小,也就是说有多少个rating[i]满足i < j 且rating[i] < rating[j]的条件,那么如果一个rating[j]之后的元素rating[k]其值比rating[j]大,那么我们就找到了DP[j]种符合从小到大排列要求的组合。同样的方法也适用于从大到小的排列。

Java代码如下:

class Solution {
    public int numTeams(int[] rating) {
        int N = rating.length;
        int count = 0;

        int[] dpIncrease = new int[N];

        for (int i=1; i<N; i++) {
            int twoIncrease = 0;
            for (int j = 0; j < i; j ++) {
                if (rating[i] > rating[j]) {
                    twoIncrease ++;
                    count += dpIncrease[j];
                }
            }
            dpIncrease[i] = twoIncrease;
        }

        int[] dpDecrease = new int[N];
        for (int i=1; i<N; i++) {
            int twoDecrease = 0;
            for (int j = 0; j < i; j ++) {
                if (rating[i] < rating[j]) {
                    twoDecrease ++;
                    count += dpDecrease[j];
                }
            }
            dpDecrease[i] = twoDecrease;
        }

        return count;
    }
}