题目描述
计算最少出列多少位同学,使得剩下的同学排成合唱队形
说明:
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足存在i(1<=i<=K)使得T1<T2<......<Ti-1<Ti>Ti+1>......>TK。
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
输入描述:
整数N
输出描述:
最少需要几位同学出列
输入例子:
8
186 186 150 200 160 130 197 200
输出例子:
4
思路:
求两次最长递增子序列,先从左往右求递增子序列a[n],采用动态规划的方法,具体见代码。再求从右到左的递增子序列b[n]。
假设输入为:
186 186 150 200 160 130 197 200
a[n] 1 1 1 2 2 1 3 4 从左到右
b[n] 3 3 2 3 2 1 1 1 从右到左
c[n] 4 4 3 5 4 2 4 5
取c[i]最大值 5, i = 3; 所以包括3这个位置左边有2个是合唱队列的,包括3这个位置右边有3个是合唱队列的。
由于3被计算了2次,所以合唱队列为:2+3-1 = 4人。
由于总人数为:8 , 所以需要抽出8-4人。
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
while(scanner.hasNext()){
int num = scanner.nextInt();
int[] arr = new int[num];
for(int i=0; i<num; i++){
arr[i] = scanner.nextInt();
}
int[] a = getBestQueue(arr, true);
int[] b = getBestQueue(arr,false);
int len = 0;
//获取最长合唱形
for(int i=0; i<num; i++){
int n = a[i] + b[i];
if(n > len){
len = n;
}
}
System.out.println(num-len+1);
}
}
//求递增子序列
public static int[] getBestQueue(int[] array, boolean acceding){
int length = array.length;
int a[] = new int[length];
if(acceding){
//从左到右的递增子序列
for(int i=0; i<length; i++){
a[i] = 1;
for(int j=0; j<i; j++){
if(array[i] > array[j]){
a[i] = Math.max(a[i], a[j]+1);
}
}
}
}else{
//从右到左的递增子序列
for(int i=length-1; i >=0 ; i--){
a[i] = 1;
for(int j=length-1; j>i; j--){
if(array[i] > array[j]){
a[i] = Math.max(a[i], a[j]+1);
}
}
}
}
return a;
}
}