华为机试题-合唱队

题目:

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

说明:

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

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


输入描述:

整数N

一行数字代表N个身高高度


输出描述:

最少需要几位同学出列


示例:

输入:

8

186 186 150 200 160 130 197 200

输出:

4


分析:

这里需要引入一个概念:最长上升序列(LIS),具体可参见【LintCode】最长上升序列(Longest Increasing Sequence)。

我们先对输入的数组从左向右计算各个位置对应的最长上升序列数值,然后从右向左计算各个位置对应的最长上升序列数值。这样我们就得到了两个数组,将这两个数组对应位置相加并减一,表示若该位置是要求中的i,那么其左半边和右半边分别都比其小,满足合唱队型,之所以减一,是因为直接相加,将i位置上的数字多算了一次。

最后我们返回两数组对应位置相加并减一的最大值,表示合唱队型的最大人数值,再用总人数减去该最大值,即是我们要求的最少需要几位同学出列。


代码:

import java.util.Scanner;

/**
 * Created by root on 7/23/17.
 */
public class Chrous {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()) {
            //输入数组长度
            int n = sc.nextInt();
            int[] nums = new int[n];
            for(int i = 0; i < n; i++) {
                nums[i] = sc.nextInt();
            }
            //输出结果
            System.out.println(resolve(nums, n));
        }
        sc.close();
    }

    public static int resolve(int[] nums, int n) {
        //从左到右的lis动归结果数组
        int[] fdp = null;
        //从右向左的lis动归结果数组
        int[] bdp = null;

        fdp = forwardDP(nums, n);
        bdp = backwardDP(nums, n);

        //保存两数组相加最大值
        int max = 0;
        for(int i = 0; i < n; i++) {
            max = Math.max(fdp[i] + bdp[i], max);
        }
        //用总人数减去(最大值-1),即是所求的最少出列人数
        return (n - (max - 1));
    }

    //求正序最长升序
    public static int[] forwardDP(int[] nums, int n) {
        //动态规划中需要的数组
        int[] lis = new int[n];
        lis[0] = 1;
        int max = 0;

        for(int i = 1; i < n; i++) {
            //找到lis[0]到lis[i-1]中最大的升序长度且nums[j]= 0; i--) {
            //找到lis[i+1]到lis[n-1]中最大的升序长度且nums[j] i; j--) {
                if(nums[j] < nums[i]) {
                    lis[i] = Math.max(lis[j], lis[i]);
                }
            }
            //加1表示该位置能构成的最长升序序长度
            lis[i] += 1;
            //更新全局长度(此处可以不必记录全局长度,因为用不到)
            max = Math.max(max, lis[i]);
        }
        return lis;
    }
}


你可能感兴趣的:(Algorithm)