• 九度 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;
    }
  • 相关阅读:
    让SiteMapDataSource能选择特定的SiteMap文件
    程序员之路──如何学习C语言(转载)
    Sql Server 2005 Express使用命令工具无法连接问题
    移远公司 NBIoT模块AT指令详细解释
    Excel自动化技术
    解析HTTP报文头
    SOAP报文下发
    双缓冲队列,生产者消费者模式
    夸孩子少用“你真棒”,教你如何夸孩子
    C++面试题相关
  • 原文地址:https://www.cnblogs.com/xinsheng/p/3585356.html
Copyright © 2020-2023  润新知