从一列数中筛除尽可能少的数使得从左往右看,这些数是从小到大再从大到小的(网易)。

题目描述:

  从一列数中筛除尽可能少的数使得从左往右看,这些数是从小到大再从大到小的(网易)。

分析:

  这可以用双端LIS方法来解决,先求一遍从左到右的,再求一遍从右到左的。最后从里面选出和最大的即可。

代码实现:

#include <iostream>

using namespace std;

int DoubleEndLIS(int *arr, int len)
{
    int *LIS = new int[len];
    int *lefToRight = new int[len];        //leftToRight[i]表示0~i最长子序列长度-1
    int *rightToLeft = new int[len];
    int maxLen = 0;        //记录总共的(上升+下降)最长子序列长度
    int low, high, mid;

    for (int i = 0; i < len; ++i)
    {
        lefToRight[i]  = 0;
        LIS[i] = 0;
    }

    LIS[0] = arr[0];
    for (int i = 1; i < len; i++)
    {
        low = 0; high = lefToRight[i-1];
        while (low <= high)
        {
            mid = (low + high)/2;
            if (LIS[mid] < arr[i])
            {
                low = mid + 1;
            }
            else
            {
                high = mid -1;
            }
        }

        LIS[low] = arr[i];
        if (low > lefToRight[i-1])
        {
            lefToRight[i] = lefToRight[i-1] + 1;    //最长子序列长度加1
        }
        else
        {
            lefToRight[i] = lefToRight[i-1];
        }
    }

    //leftToRight的每个值增加1,因为他们是最长子序列值-1
    //此时leftToRight表示的是最长子序列的真正值。
    for (int i = 0; i < len; i++)
    {
        lefToRight[i]++;
    }

    //从右到左
    for (int i = 0; i < len; i++)
    {
        rightToLeft[i] = 0;
        LIS[i] = 0;
    }

    int k = 0;
    LIS[0] = arr[len-1];
    for (int i = len -2; i >= 0; --i)
    {
        low = 0; high = rightToLeft[k];
        while (low <= high)
        {
            mid = (low + high)/2;
            if (LIS[mid] < arr[i])
            {
                low = mid + 1;
            }
            else
            {
                high = mid - 1;
            }
        }

        LIS[low] = arr[i];
        if (low > rightToLeft[k])
        {
            rightToLeft[k+1] = rightToLeft[k] + 1;
        }
        else
        {
            rightToLeft[k+1] = rightToLeft[k];
        }
        ++k;
    }

    for (int i = 0; i < k; ++i)
    {
        rightToLeft[i]++;
    }

    //求最大值即为要求的
    for (int i = 0; i < len; ++i)
    {
        cout<<"i: "<<i<<" "<<lefToRight[i]<<"  "<<rightToLeft[len-i-1]<<endl;
        if (lefToRight[i] + rightToLeft[len-i-1] > maxLen)
            maxLen = lefToRight[i] + rightToLeft[len-i-1];
    }
    cout<<"maxLen:"<<maxLen<<endl;

    delete LIS;
    delete lefToRight;
    delete rightToLeft;

    return len - maxLen + 1;
}

int main()
{
    int arr[] = {1,5,7,6,9,3,8,4,2};
    int ret;
    ret = DoubleEndLIS(arr, 9);
    cout<<ret<<endl;

    return 0;
}

参考:http://blog.csdn.net/nciaebupt/article/details/8466049

但是,他的程序有问题,我做了修改。

时间: 2024-12-29 11:37:50

从一列数中筛除尽可能少的数使得从左往右看,这些数是从小到大再从大到小的(网易)。的相关文章

利用栈判断输入的表达式中的括号是否匹配(假设只含有左、右括号)

利用栈判断输入的表达式中的括号是否匹配(假设只含有左.右括号) bool Match(char exp[],int n) { int i=0; char e; bool match=true; SqStack *st; InitStack(st);//初始化栈 while(i<n && match)//扫描exp中所有字符 { if(exp[i]=='(')//当前字符为左括号,将其进栈 Push(st,exp[i]); else if(exp[i]==')')//当前字符为右括号

Fine-tuning Convolutional Neural Networks for Biomedical Image Analysis: Actively and Incrementally如何使用尽可能少的标注数据来训练一个效果有潜力的分类器

作者:AI研习社链接:https://www.zhihu.com/question/57523080/answer/236301363来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 今天我给大家介绍一下 CVPR 2017 关于医学图像处理的一篇比较有意思的文章,用的是 active learning 和 incremental learning 的方法. 今天分享的主要内容是,首先介绍一下这篇文章的 motivation,就是他为什么要做这个工作:然后介绍一下他

在一个每一行从左到右递增每一列从上到下递增的二维数组中查找一个整数是否存在——3

给定一个二维数组,数组的特点是:每一行从左到右数据大小依次递增,每一列数据从上到下依次递增,要求判断一个整数是否在这个二维数组中: 设计二维数组如下: 首先,毋庸置疑的的是,遍历一遍数组肯定能判断出来,这也是最笨的方法了,因此,要想提高程序的运行效率就得找出一种高效的方法来查找: 一开始的想法大概都能想到从数组第一行第一列的数开始沿着对角线判断,如果是对角线数据就可以直接返回,比如我们要想查找17这个数,这时候17比0.9.16都要大,因此以0.9.16为对角线的矩形数据就可以排除了,接下来判断

剑指offer系列——二维数组中,每行从左到右递增,每列从上到下递增,设计一个算法,找其中的一个数

题目:二维数组中,每行从左到右递增,每列从上到下递增,设计一个算法,找其中的一个数 分析: 二维数组这里把它看作一个矩形结构,如图所示: 1 2 8 9 2 4 9 12 4 7 10 13 6 8 11 15 在做这道题的时候我最先考虑的是每次比较对角线上的元素可能可以取得较好的效果, 以查找9为例, 从1(0,0)开始,1<10,可以得出结论,10在1的右侧或下侧: 1 2 8 9 2 4 9 12 4 7 10 13 6 8 11 15 然后看4(1,1),4<9, 1 2 8 9 2

巧妙使用Contains()方法查找一个数是否在某堆数中

问题:要判断用户输入的一个数,或者是程序里方法的一个参数的值,或者是一个变量的值是否在某堆数中. 简洁写法:把这堆数放在list中,使用list的Contains()方法检查list是否包含这个数,取反. 代码如下: static void Main(string[] args) { Console.WriteLine("请输入一个数字:"); string input=Console.ReadLine(); if (!(new List<string>() { "

从1到n的数中总共包含1的个数

1. 题目 求从1到n的数中,总共包含了多少个1 2. 分析 令X=x1x2-xm为1到n之间的一个整数,显然X为一个m位的整数.例如X=21345时,对应x1=2,x2=1,x3=3,x2=4,x3=5.题目求解过程如下: (1) 将X分成0~X1与X1+1~X两部分,其中X1=x2-xm.若此时X只有一位则X1=0,实际实现时用字符串表示数字X,当X只有一位时移至字符串末尾'\0'. (2) 第二部分X1+1~X分为3种情况求解: a) x1 > 1, a_1) 最高位为1的共p1=10m-

温故知新,基础复习(一个有序从大到小不重复的数列,任意给出一个sum值,求出数列中所有满足和为sum的数对)

温故知新,基础复习(一个有序从大到小不重复的数列,任意给出一个sum值,求出数列中所有满足和为sum的数对) #include<stdio.h> #include<stdlib.h> void PrintSumNumbers(int Arra[],int ASize,int Sum) { //O(1) if (ASize<2) { printf("The size of the Arra is invalid.\n"); return; } if(Sum&

三数中找最大值

static void Main11三数中找最大值(string[] args) { //1.输入三个数,找出最大的输出 Console.WriteLine("请输入第一个数"); int a = Convert.ToInt32(Console.ReadLine()); Console.WriteLine("请输入第二个数"); int b = Convert.ToInt32(Console.ReadLine()); Console.WriteLine("

找出十进制数中出现的&#39;&#39;一&#39;&#39;的个数

一.题目要求: 给定一个十进制的正整数,写下从1开始,到N的所有整数,然后数一下其中出现“1”的个数. 要求: 1.写一个函数 f(N) ,返回1 到 N 之间出现的“1”的个数.例如 f(12)  = 5. 2.在32位整数范围内,满足条件的“f(N) =N”的最大的N是多少. 二.解决思路 通过列举几个数进行计算,可以发现函数f(N)规律如下: 1.一位十进制数:当N>=1时,f(N)=1:当N=0时,f(N)= 0; 2.两位十进制数:f(13)=个位出现1的个数+十位出现1的个数=2+4