九度 1500:出操队形(LIS变形)

题目描述:

在读高中的时候,每天早上学校都要组织全校的师生进行跑步来锻炼身体,每当出操令吹响时,大家就开始往楼下跑了,然后身高矮的排在队伍的前面,身高较高的就要排在队尾。突然,有一天出操负责人想了一个主意,想要变换一下队形,就是当大家都从楼上跑下来后,所有的学生都随机地占在一排,然后出操负责人从队伍中抽取出一部分学生,使得队伍中剩余的学生的身高从前往后看,是一个先升高后下降的“山峰”形状。据说这样的形状能够给大家带来好运,祝愿大家在学习的道路上勇攀高峰。(注,山峰只有一边也符合条件,如1,1、2,2、1均符合条件)

 

思路

1. 这道题我还蛮想总结一下, 因为与之类似的一道题 Candy 当时就把我做崩溃了. 并且, Leetcode 上买卖股票问题和这个也很类似.

2. 这道题实际上比买卖股票还有简单些. 买卖股票从左到右需要 dp 一遍, 从右到左还需要一遍 dp, 并且函数需要各写各的, 因为我们需要求解的是从左向右上升的序列, 而这道题计算的是两个序列, 分别是从左到右递增和从右到左递增. 这样的话先计算从左到右的, 然后 reverse 数组, 再计算一遍又从右到左的即可, 函数只需要写一个.

3. 写完 LIS, 最后就要讨论边界了. 题目说 11, 22, 1 都算有效的, 但第二个案例却返回 4 , 有些纠结.

 

代码 未通过九度测试

#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;

int longest1[100005];
int longest2[100005];

int height[100005];


int record1[100005];
int record2[100005];

int search(int x, int n, int *record) {
    int low = 0, high = n-1;

    while(low <= high) {
        int mid = (low+high)>>1;

        if(record[mid] == x) {
            return mid;
        }else if(record[mid] > x) {
            high = mid -1;
        }else{
            low = mid + 1;
        }
    }
    return low;
}

void lt2rt(int n, int *record, int *longest, int first) {
    int len = 1;
    record[0] = first;
    longest[0] = 1;
    for(int i = 1; i < n; i ++) {
        if(height[i] > record[len-1]) {
            record[len] = height[i];
            len++;
        }else{
            int pos = search(height[i], len, record);
            record[pos] = height[i];
        }
        longest[i] = len;
    }
}


int main() {
    
    int n;
    while(scanf("%d", &n) != EOF) {
        for(int i = 0; i < n; i ++)
            scanf("%d", height+i);

        lt2rt(n, record1, longest1, height[0]);

        reverse(height, height+n);
        lt2rt(n, record2, longest2, height[n-1]);

        int maxnum = 0;
        for(int i = 0; i < n-1; i ++) {
            int left = longest1[i];
            int right = longest2[n-i-2];
            maxnum = max(maxnum, left+right);
        }
        maxnum = max(maxnum, longest2[n-1]);
        maxnum = max(maxnum, longest1[n-1]);

        cout << n-maxnum << endl;
    }
    return 0;
}

 

posted @ 2014-03-06 21:18  SangS  阅读(334)  评论(0编辑  收藏  举报