华为机试题——合唱队

题目描述

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

说明:

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; } }
 
 
原文地址:https://www.cnblogs.com/huangyichun/p/6389086.html