牛客网力扣算法编程之二 |动态规划 - 合唱队-Java代码实现

【算法编程】-合唱队

题目描述

       计算最少出列多少位同学,使得剩下的同学排成合唱队形

        说明:

      N 位同学站成一排,音乐老师要请其中的 (N - K) 位同学出列,使得剩下的 K 位同学排成合唱队形。
     合唱队形是指这样的一种队形:设K位同学从左到右依次编号为 1,2…,K ,他们的身高分别为 T1,T2,…,TK ,   则他们的身高满足存在 i (1<=i<=K) 使得 T1<T2<......<Ti-1<Ti>Ti+1>......>TK 。

     你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

        注意:不允许改变队列元素的先后顺序 且 不要求最高同学左右人数必须相等

        请注意处理多组输入输出!

        数据范围: 1≤n≤3000

输入描述:

        有多组用例,每组都包含两行数据,第一行是同学的总数 N ,第二行是 N 位同学的身高,以空格隔开

输出描述:

        最少需要几位同学出列

示例1

        输入:

        8
        186 186 150 200 160 130 197 200

        输出:

        4
说明:由于不允许改变队列元素的先后顺序,所以最终剩下的队列应该为186 200 160 130或150 200 160 130       

解题思路总结:

合唱团站位:站中间的个子最高,然后沿左右两边依次降低,问我们最少抽出多少个人,组成合唱团站位。

1. 采用nextInt保存整数k,数组arr[];因需要处理多组数据,最外层加上while(sc.hasNextInt());

2. 定义两个动态规划DP数组arrL[]和arrR[],长度与接收的元素数组arr[]相同,均为k;

3. arrL和arrR数组分别用于保存从左边和右边遍历每个元素,其右边和左边元素比他小的满足 T1<T2<......<Ti-1<Ti>Ti+1>......>TK,

4.动态规划代码在循环遍历里,初始化每个DP值arrL[i]=0,动态规划方程:arrL[i] = Math.max(arrL[j] + 1, arrL[i]),同理,反向遍历求得arrR[i]数组;

5.划重点+敲黑板: 每个元素0-k,已经算出了他左边和右边能组成的最大递减序列人数,可以组成的最长合唱团成员的数量,依次把各个成员作为最高选手,对他左边和右边的最大递减序列人数相加,再加上他自己,即为每个人作为最高选手可以组成的最长合唱团站位,用maxValue遍历保存其中的最大值:maxValue = Math.max(arrL[i] + arrR[i] + 1, maxValue);

6.题目问最少出列的人数,即为k-maxValue。这几个人出列就是最长合唱团站位。

此题的关键是掌握动态规划三部曲,代码如下,希望大家能看懂:

import java.util.*;
public class Main {
     public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        while (sc.hasNextInt()) {
            int k = sc.nextInt();

            int[] arr = new int[k];
            for (int i = 0; i < k; i++) {
                arr[i] = sc.nextInt();
            }
            int[] arrL = new int[k];
            int[] arrR = new int[k];

            for (int i = 0; i < k; i++) {
                arrL[i] = 0;
                for (int j = 0; j < i; j++) {
                    if (arr[j] < arr[i]) {
                        arrL[i] = Math.max(arrL[j] + 1, arrL[i]);
                    }
                }
            }
            for (int i = k - 1; i >= 0; i--) {
                arrR[i] = 0;
                for (int j = k - 1; j > i; j--) {
                    if (arr[j] < arr[i])
                        arrR[i] = Math.max(arrR[j] + 1, arrR[i]);
                }
            }

            int maxValue = 0;
            for (int i = 0; i < k; i++) {
                maxValue = Math.max(arrL[i] + arrR[i] + 1, maxValue);
            }
            System.out.println(k - maxValue);

        }
    }


}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

国林哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值