题解 | #合唱队#

合唱队

https://www.nowcoder.com/practice/6d9d69e3898f45169a441632b325c7b4

import java.util.Scanner;
import java.util.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // // 注意 hasNext 和 hasNextLine 的区别
        // while (in.hasNextInt()) { // 注意 while 处理多个 case
        //     int a = in.nextInt();
        //     int b = in.nextInt();
        //     System.out.println(a + b);
        // }
        int num = in.nextInt();   //总人数
        if(num <=1){
            System.out.println(0); // 不需要出列
        }
        int[] height = new int[num];
        //填充身高数组
        for(int i=0; i<num; i++){
            height[i] = in.nextInt();
        }

        //动态规划:(基础思路)最长递增子序列
        /**
            1. 先找每个位置i的最长递增子序列;
            2. 再找出每个位置i为开始点的最长递减子序列;
            3. 最长合唱队长度=最长递增子序列 + 最长递减子序列 -1
            4. 需要出列的人数就是: 原长度 - 最长合唱队长度         
         */ 

        // 1. 最长递增子序列
        // leftDp[i] 代表的意思: 0-i个元素的最长递增子序列的长度
        // 推导公式: leftDp[i] = max(leftDp[i], leftDp[j] +1)      //leftDp[i]初始化为1,至少有1个元素
        // 说明leftDp[j] (i外层循环,j内层循环从 0 -i遍历,如果出现j<i, height[i]>height[j] , 则出现递增,可以加1)
        int[] leftDp = new int[num];
        //初始化数组,整个数组每个位置的初始值至少为1
        Arrays.fill(leftDp, 1);
        for(int i =1; i<num; i++){
            for(int j =0; j<i; j++){
                //当j<i时,且出现height[j] < height[i],则序列长度+1,相等不算
                if(height[j] < height[i]){
                    leftDp[i] = Math.max(leftDp[i], leftDp[j]+1);     
                }
            }
        }

        // 2. 每个位置i往后的最长递减序列, 即起始位置为数组尾,到i位置是最长递增子序列
        // rightDp[i] 代表的意思是:从数组最后一个,向前遍历到i,最长递增子序列长度
        int[] rightDp = new int[num];
        Arrays.fill(rightDp,1);
        for(int i=num-2; i>=0; i--){
            //当j>i,且出现height[j] > height[i],则序列长度+1,相等不算
            for(int j=num-1; j>i; j--){
                if(height[j] < height[i]){
                    rightDp[i] = Math.max(rightDp[i], rightDp[j] +1);
                }
            }
        }

        //3. sing[i]: 每个位置下的最长合唱队长度,以i为中心向两边散开,并记录一个最大值
        int[] sing = new int[num];
        int maxLength =0;
        for(int i=0; i<num; i++){
            sing[i] = leftDp[i] + rightDp[i] -1;
            maxLength = Math.max(maxLength, sing[i]);
        }

        //4. 需要出列的人数就是 原始人数num-maxLength
        System.out.println(num - maxLength); 
    }
}

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务