【牛客网 - 华为机试】HJ24 合唱队——最长上升子序列
题目描述
计算最少出列多少位同学,使得剩下的同学排成合唱队形
说明:
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足存在i(1<=i<=K)使得T1<T2<…<Ti-1Ti+1>…>TK。
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
注意不允许改变队列元素的先后顺序
请注意处理多组输入输出!
输入描述:
整数N
输出描述:
最少需要几位同学出列
示例1
输入
8
186 186 150 200 160 130 197 200
输出
4
解题思路
- 学生战队的位置是不变的。
- 合唱排序顺序:矮 - 高 -矮
这道题考的是常见的最长上升子序列问题。
- 先找到每一个位置i左侧的最长上升子序列长度
int[] l
:每一个位置左侧最长子序列长度等于其左侧比它小的所有位置的最长子序列长度中的最大值+1 - 再找到每一个位置i右侧的最长下降子序列长度
int[] r
:每一个位置右侧最长子序列长度等于其右侧比它小的所有位置的最长子序列长度中的最大值+1 - 然后求出
所有位置的最长序列长度=左侧最长子序列长度+右侧最长子序列长度-1
(因为该位置被算了两次,所以减1) - 然后用
所有长度减去最长序列长度
就是答案
/**
* Copyright (C), 2019-2021
* author candy_chen
* date 2021/4/24 15:37
*
* @Classname HJ24
* Description: 合唱队
*/
import java.util.Scanner;
/**
* 合唱排序顺序:矮 - 高 -矮
*/
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()){
int total = sc.nextInt();
int[] arr = new int[total + 1];
for (int i = 1;i <= total;i++){
arr[i] = sc.nextInt();
}
int[] l = left(arr); //求整个数组中,上升子序列长度,并存入l[]数组中
int[] r = right(arr); //求整个数组中,递减子序列长度,并存入r[]数组中
int max = 0;
for (int i = 0;i < arr.length;i++){
if (max < (l[i] + r[i] - 1)){
max = l[i] + r[i] - 1;
}
}
System.out.println(total - max);
}
}
//求上升子序列长度
private static int[] left(int[] arr) {
int[] left = new int[arr.length];
for (int i = 1;i < arr.length;i++){
left[i] = 1;
for (int j = 1;j < i;j++){
if (arr[j] < arr[i]){
left[i] = Math.max(left[i],left[j] + 1);
}
}
}
return left;
}
//求右序列的递减子序列长度
private static int[] right(int[] arr) {
int[] right = new int[arr.length];
for (int i = arr.length - 1;i > 0;i--){
right[i] = 1;
for (int j = arr.length - 1;j > i;j--){
if (arr[j] < arr[i]){
right[i] = Math.max(right[i],right[j]+1);
}
}
}
return right;
}
}