Java题解 | HJ24 #合唱队#

合唱队

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

描述

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

说明:

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

解法

此题考查的是动态规划算法,属于最长上升子序列问题。注意几个点:

  • 学生站队的位置是不变的。
  • 合唱排序顺序:矮 - 高 -矮

先找到每一个位置i左侧的最长上升子序列长度int[] l:每一个位置左侧最长子序列长度等于其左侧比它小的所有位置的最长子序列长度中的最大值+1;

再找到每一个位置i右侧的最长下降子序列长度int[] r:每一个位置右侧最长子序列长度等于其右侧比它小的所有位置的最长子序列长度中的最大值+1;

然后求出所有位置的最长序列长度=左侧最长子序列长度+右侧最长子序列长度-1(因为该位置被算了两次,所以减1);

最后用所有长度减去最长序列长度就是答案。

 

 /*
  *  Copyright (c) waylau.com, 2022. All rights reserved.
 */
 
package com.waylau.nowcoder.exam.oj.huawei;

import java.util.Scanner;

/**
 * HJ24 合唱队.
 * 计算最少出列多少位同学,使得剩下的同学排成合唱队形
 * 说明: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 位同学的身高,以空格隔开
 * 输出描述:最少需要几位同学出列
 *
 * @author <a href="https://waylau.com">Way Lau</a>
 * @since 2022-08-15
 */
public class HJ024Chorus {

    public static void main(String[] args) {
        // 输入
        Scanner sc = new Scanner(System.in);

        while (sc.hasNext()) {
            int n = sc.nextInt();
            int[] arr = new int[n];

            for (int i = 0; i < n; i++) {
                arr[i] = sc.nextInt();
            }

            int[] left = getAscendingSubsequence(arr);
            int[] right = getDescendingSubsequence(arr);
            
            int max = 0;
            for (int i = 0; i < n; i++) {
                int result = left[i] + right[i] - 1;
                max = Math.max(max, result);
            }

            // 输出
            System.out.println(n - max);
        }

        // 关闭
        sc.close();

    }

    // 上升子序列长度
    private static int[] getAscendingSubsequence(int[] arr) {
        int[] result = new int[arr.length];
        for (int i = 0; i < result.length; i++) {
            result[i] = 1;
            for (int j = 0; j < i; j++) {
                if (arr[j] < arr[i]) {
                    result[i] = Math.max(result[i], result[j] + 1);
                }
            }

        }
        return result;
    }

    // 递减子序列长度
    private static int[] getDescendingSubsequence(int[] arr) {
        int[] result = new int[arr.length];
        for (int i = result.length - 1; i >= 0; i--) {
            result[i] = 1;
            for (int j = result.length - 1; j > i; j--) {
                if (arr[j] < arr[i]) {
                    result[i] = Math.max(result[i], result[j] + 1);
                }
            }

        }
        return result;
    }
}

参考引用

#华为机考#
全部评论

相关推荐

行云流水1971:这份实习简历的优化建议: 结构清晰化:拆分 “校园经历”“实习经历” 板块(当前内容混杂),按 “实习→校园→技能” 逻辑排版,求职意向明确为具体岗位(如 “市场 / 运营实习生”)。 经历具象化:现有描述偏流程,需补充 “动作 + 数据”,比如校园活动 “负责宣传” 可加 “运营公众号发布 5 篇推文,阅读量超 2000+,带动 300 + 人参与”;实习内容补充 “协助完成 XX 任务,效率提升 X%”。 岗位匹配度:锚定目标岗位能力,比如申请运营岗,突出 “内容编辑、活动执行” 相关动作;申请市场岗,强化 “资源对接、数据统计” 细节。 信息精简:删减冗余表述(如重复的 “负责”),用短句分点,比如 “策划校园招聘会:联系 10 + 企业,组织 200 + 学生参与,到场率达 85%”。 技能落地:将 “Office、PS” 绑定经历,比如 “用 Excel 整理活动数据,输出 3 份分析表;用 PS 设计 2 张活动海报”,避免技能单独罗列。 优化后需强化 “经历 - 能力 - 岗位需求” 的关联,让实习 / 校园经历的价值更直观。 若需要进一步优化服务,私信
实习,投递多份简历没人回...
点赞 评论 收藏
分享
评论
3
1
分享

创作者周榜

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