最长递增子序列和网易去除最少使从左向右递增又递减问题

(1)最长递增子序列问题

有两种方法:(1)动态规划方法(2)类似二分查找的方法O(nlogn)

动态规划方法:

以i结尾的序列的最长递增子序列和其[0, i - 1]“前缀”的最长递增子序列有关,设LIS[i]保存以i结尾的最长递增子序列的长度:
    若i = 0,则LIS[i] = 1;
    若i > 0,则LIS[i]的值和其[0, i - 1]前缀的最长递增子序列长度有关,用j遍历[0, i - 1]得到其最长递增子序列为LIS[j],对每一个LIS[j],如果序列array[j]  < array[i]并且LIS[j] + 1 > LIS[i],则LIS[i]的值变成LIS[j] + 1。即:
    LIS[i] = max{1, LIS[j] + 1},其中array[i] > array[j] 且 j = [0, i - 1]。

代码如下:

。。。。。晚上补充上

(2)采用类似二分查找方法

假设存在一个序列d[1...9] = 2 1 5 3 6 4 8 9 7,可以看出它的LIS长度是5。
    下面一步一步试着找到它。
    我们定义一个序列B,然后令i = 1 to 9逐个考察这个序列。
    此外,我们用一个变量len来记录现在的最长算到多少。
    首先,把d[1]有序的放到B中,令B[1] = 2,就是说当只有一个数字2的时候,长度为1的LIS的最小末尾是2,这时len = 1;
    然后,把d[2]有序的放到B中,令B[1] = 1,就是说长度为1的LIS的最小末尾是1,d[1] = 2已经没用了,很容易理解吧,这时len = 1;
    接着,d[3] = 5,d[3] > B[1],所以令B[1 + 1] = B[2] = d[3] = 5,就是说长度为2的LIS的最小末尾是5,很容易理解吧,这时B[1...2] = 1, 5,len = 2;
    再来,d[4] = 3,它正好在1,5之间,放在1的位置显然不合适,因为1小于3,长度为1的LIS最小末尾应该是1,这样很容易推知,长度为2的LIS最小末尾是3,于是可以把5淘汰掉,这时B[1...2] = 1,3,len = 2;
    继续,d[5] = 6,它在3的后面,因为B[2] = 3,而6在3后面,于是很容易推知B[3] = 6,这时B[1...3] = 1,3,6,还是很容易理解吧?这时len = 3;
    第6个,d[6] = 4,你看它在3和6之间,于是就可以把6替换掉,得到B[3] = 4。B[1...3] = 1,3,4,这时len = 3;
    第7个,d[7] = 8,它很大,比4大,于是B[4] = 8,这时len = 4;
    第8个,d[8] = 9,得到B[5] = 9,len继续增大,这时len = 5;
    最后一个,d[9] = 7,它在B[3] = 4和B[4] = 8之间,所以我们知道,最新的B[4] = 7, B[1...5] = 1,3,4,7,9,len = 5。
    于是我们知道了LIS的长度为5。
    注意,注意。这个1,3,4,7,9不是LIS,它只是存储了对应长度LIS的最小末尾。有了这个末尾,我们就可以一个一个地插入数据。虽然最后一个 d[9] = 7更新进去对于这个数组数据没有什么意义,但是如果后面再出现两个数字8和9,那么就可以把8更新到d[5],9更新到d[6],得到LIS的长度为6。
    然后应该发现一件事情了:在B中插入数据是有序的,而且进行替换而不需要移动——也就是说,可以使用二分查找,将每一个数字的插入时间优化到O(logn),于是算法的时间复杂度就降低到了O(nlogn)了。

代码如下:

 

 1 int findlis(int *A,int n,int *lefttoright)     //从左向右最长递增子序列  
 2 {
 3     if(A==NULL||n<0)
 4         return -1;
 5     int *lis=new int[n];
 6     //int *lefttoright=new int[n];
 7     lefttoright[0]=1;                    //lefttoright[i]保存从左到右,以i为终点的最长递增子序列长度,注意已经是正常的长度了,不是小一了
 8     int max=0;                           //max是lis[]的最大下标如lis[]={1,2,4}时,max=2;
 9     lis[0]=A[0];
10     for(int i=1;i<n;i++)
11     {
12         int left=0;
13         int right=max;
14         while(left<=right)            //这个二分查找就是最终left落到指定位置例如lis[]={1,2,4},若A[i]=5,left=3(从0开始),则更新为lis[]={1,2,4,5};lis[]={1,2,4},若A[i]=3,left=2,则更新为lis[]={1,2,3};
15         {
16             int mid=(left+right)/2;
17             if(A[i]>lis[mid])
18                 left=mid+1;
19             else
20                 right=mid-1;
21         }
22         lis[left]=A[i];
23         lefttoright[i]=left+1;    //lefttoright[i]等于left加一,同返回时是max+1同样道理
24         if(left>max)          //如果left>max,则让max=left
25             max++;
26     }
27     delete lis;
28     return max+1;             //注意,必须返回max+1,才是最终结果max是最长递增子序列长度减一
29 }

下面就开始实现“从一列数中筛除尽可能少的数使得从左往右看,这些数是从小到大再从大到小的“这个问题。
双端LIS问题,用动态规划的思想可以解决,目标规划函数为max{B[i] + C[i] - 1},其中B[i]是从左到右的,0~i个数之间满足递增的数字个数;C[i]为从右到左的,n- 1 ~ i个数之间满足递增的数字个数。最后结果为n- max + 1,其中动态规划的时候,可以用二分查找进行处理,如上述求最长递增子序列的方法二。

代码如下:
 1 #include <iostream>
 2 using namespace std;
 3 
 4 //最长递增子序列的O(nlogn)方法
 5 //lis[i]表示最长递增子序列的长度的i+1的最小的最后一个元素
 6 
 7 int findlis(int *A,int n,int *lefttoright)     //从左向右最长递增子序列  
 8 {
 9     if(A==NULL||n<0)
10         return -1;
11     int *lis=new int[n];
12     //int *lefttoright=new int[n];
13     lefttoright[0]=1;                    //lefttoright[i]保存从左到右,以i为终点的最长递增子序列长度,注意已经是正常的长度了,不是小一了
14     int max=0;                           //max是lis[]的最大下标如lis[]={1,2,4}时,max=2;
15     lis[0]=A[0];
16     for(int i=1;i<n;i++)
17     {
18         int left=0;
19         int right=max;
20         while(left<=right)            //这个二分查找就是最终left落到指定位置例如lis[]={1,2,4},若A[i]=5,left=3(从0开始),则更新为lis[]={1,2,4,5};lis[]={1,2,4},若A[i]=3,left=2,则更新为lis[]={1,2,3};
21         {
22             int mid=(left+right)/2;
23             if(A[i]>lis[mid])
24                 left=mid+1;
25             else
26                 right=mid-1;
27         }
28         lis[left]=A[i];
29         lefttoright[i]=left+1;    //lefttoright[i]等于left加一,同返回时是max+1同样道理
30         if(left>max)          //如果left>max,则让max=left
31             max++;
32     }
33     delete lis;
34     return max+1;             //注意,必须返回max+1,才是最终结果max是最长递增子序列长度减一
35 }
36 
37 int findrighttoleftincrease(int *A,int n,int * righttoleft)  //从右向左最长递增子序列,也可以说成是从左向右最长递减子序列
38 {
39     if(A==NULL||n<0)
40         return -1;
41     int *lis=new int[n];
42     //int *righttoleft=new int[n];
43     lis[0]=A[n-1];           //lis[0]=为A【n-1]
44     righttoleft[n-1]=1;      //注意是lefttoright[n-1]=1
45     int max=0;
46     int left,right;
47     for(int i=n-2;i>=0;i--)
48     {
49         left=0;
50         right=max;
51         while(left<=right)
52         {
53             int mid=(left+right)/2;
54             if(A[i]>lis[mid])
55                 left=mid+1;
56             else
57                 right=mid-1;
58         }
59         lis[left]=A[i];
60         righttoleft[i]=left+1;
61         if(left>max)                  //其实这时,max++后,max==left
62             max++;
63     }
64     delete lis;
65     return max++;
66 }
67             
68 
69 int main()
70 {
71     //网易的去掉最少元素使得从左向右递增然后递减,即为从左向右递增然后递减的最大值
72     //Big=max(lefttoright[i]+righttoleft[i]-1}
73     //所求即为n-Big。
74     int A[]={2,3,5,1,6,9,10,15,1};
75     int *lefttoright=new int[9];
76     int *righttoleft=new int[9];
77     int maxleft=findlis(A,9,lefttoright);
78     if(maxleft==-1)
79         cout<<"wrong"<<endl;
80     else
81         cout<<"max num lefttoright= "<<maxleft<<endl;
82     int maxright=findrighttoleftincrease(A,9,righttoleft);
83     if(maxright==-1)
84         cout<<"wrong"<<endl;
85     else
86         cout<<"max num righttoleft= "<<maxright<<endl;
87     int max=0;
88     for(int i=0;i<9;i++)
89     {
90         if(lefttoright[i]+righttoleft[i]-1>max)
91             max=lefttoright[i]+righttoleft[i]-1;
92     }
93     cout<<"去除"<<9-max<<endl;
94     delete lefttoright;
95     delete righttoleft;
96     system("pause");
97 }

完。

 

 

 

转载于:https://www.cnblogs.com/zmlctt/p/3842501.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/546392.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux debian 11上安装 Google Chrome浏览器教程

Google Chrome简介 Google Chrome是世界上最受欢迎的网络浏览器。它是为现代网络构建的快速&#xff0c;安全的浏览器。Chrome不是开放源代码的浏览器&#xff0c;也不包含在官方Debian存储库中。它基于Chromium&#xff0c;这是一个默认Debian Buster存储库中可用的开源浏览器…

面试官 | 线程间是如何通信的?

作者 | wingjay来源 | wingjay.com正常情况下&#xff0c;每个线程独立完成自己的任务就结束了&#xff0c;但某些特殊情况下&#xff0c;我们需要多个线程来共同完成某项任务&#xff0c;这时就涉及到了线程间通信了。本文涉及到的知识点&#xff1a;thread.join()object.wait…

Linux debian解压和压缩.rar文件教程

一、简介 我们上传到Linux服务器上的文件日常是.zip或.tat.gz的文件&#xff0c;我们可以用相应的命令对文件进行解压。有时会遇到.rar文件。本次使用rar软件版本是5.6.0。官方网站为http://www.rarlab.com/ 二、下载和安装rar文件 1.创建文件夹 [rootdoudou ~]# mkdir /us…

windos手工扩展分区

为什么80%的码农都做不了架构师&#xff1f;>>> windows 2003系统下手工扩展分区&#xff08;2008系统直接在磁盘管理里扩展卷即可&#xff09; 1、虚拟机关机&#xff0c;将目标磁盘扩展到所需大小 2、开机&#xff0c;进入命令行模式 3、diskpart 进入diskpart工…

面试突击 | 彻底搞定 JVM 这几道高频面试题

前言 Java 相比 C/C 最显著的特点便是引入了自动垃圾回收 (下文统一用 GC 指代自动垃圾回收)&#xff0c;它解决了 C/C 最令人头疼的内存管理问题&#xff0c;让程序员专注于程序本身&#xff0c;不用关心内存回收这些恼人的问题&#xff0c;这也是 Java 能大行其道的重要原因之…

Linux五种清理系统垃圾的方式

​ Linux系统使用时间长了&#xff0c;安装了很多软件&#xff0c;更新了不少的软件包&#xff0c;会导致Linux系统反应速度严重下降。下面有5种清理Linux系统下冗余垃圾的命令&#xff0c;总共有sudo apt-get下的clean、autoclean、autoremove、remove、purge。 一、clean命令…

Linux——curl(转)

先介绍curl工具的使用&#xff0c;在其他文章中介绍如何使用curl发送Identity API linux curl是一个利用URL规则在命令行下工作的文件传输工具。它支持文件的上传和下载&#xff0c;所以是综合传输工具&#xff0c;但按传统&#xff0c;习惯称url为下载工具。  一&#xff0c…

阿里面试官给你的一些忠告,这样做肯定错不了!附视频

作者 | 梦游的龙猫来源 | http://dwz.win/2pU近期面试了许多&#xff0c;真的是许多同学&#xff0c;讲道理其实我是比较有耐心的面试官&#xff0c;但是还是忍不住想要吐槽&#xff0c;因此写下这篇文章&#xff0c;一方面希望可以帮助到正在面试&#xff0c;或者在来面试路上…

Linux debian ubuntu安装.deb包教程

deb包是debian&#xff0c;ubuntu等LINUX发行版的软件安装包。 首先deb包已下载保存电脑上&#xff0c;deb包安装方法有两种&#xff1a; 一、可以直接“双击”安装 二、手动安装 使用终端命令行安装 1.使用ctrl alt T组合键打开终端&#xff0c;输入并执行下面命令&…

VMware vCloud® Suite 5.5功能介绍

2013年8月26日在旧金山举办的VMworld大会上&#xff0c;VMware宣布推出VMware vCloud Suite 5.5&#xff0c;它是全面且集成的云基础架构与管理软件套件。新版本让客户能够利用软件定义的数据中心架构&#xff0c;建设并运营基于vSphere的私有云。VMware vCloud Suite 5.5让客户…

Java面试详解(2020版):500+ 面试题和核心知识点详解

与其在网上拼命的找面试题&#xff0c;不如加入我们畅快的阅读。为了写好这些面试题&#xff0c;我先后拜访了一二十家互联网公司&#xff0c;与不同的面试官和面试者进行面对面探讨&#xff0c;深入了解了企业对于面试者的要求和常见的 Java 面试题型。之后我花了大半年的时间…

Linux debian安装Vim和Vim使用教程

Vim 是一个开源免费工具&#xff0c;具有命令行界面和图形用户界面。它对于编辑用 shell、python、Perl、c/c 等编写的配置文件和程序特别有用。最新版本的 Vim 包括一些新功能、错误修复和文档更新。 Vim安装步骤 步骤一、首先使用下面命令更新一下系统&#xff0c;确保您的…

[笔记]Linux NTP命令 (ESX适用)

原创作品&#xff0c;允许转载&#xff0c;转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://delxu.blog.51cto.com/975660/307513【推荐阅读】这篇最好&#xff1a;http://wiki.ubuntu.org.cn/Quick_HOWTO_:_Ch24_:_The_NTP_Server…

给所有开发人员的 11 条忠告(第 4 条亮了)

1、初学者尽量去有成熟技术团队的公司 其实很多小型的互联网创业公司只有一两个人技术人员&#xff0c;如果里面有大牛能带你成长还好&#xff0c;但大部分估计都是要你自己去摸索学习来解决公司的问题&#xff0c;对个人成长其实是很慢长对过程&#xff0c;相反如果你去大厂&a…

Linux debian安装Notepadqq,Linux系统下的Notepad++编辑器

Notepad是Windows系统常用的文本编辑器&#xff0c;而Notepadqq是Linux系统下Notepad的免费开源替代品。 在Debian系统中安装Notepadqq的方法 Debian也可以像Ubuntu系统一样使用PPA来安装Notepadqq&#xff0c;但我们需要手动添加PPA。 1.打开终端&#xff0c;使用以下命令&…

Codeforces Round #FF

A.DZY Loves Hash hash函数 h(x) x % p  输出第一次冲突的位置 #include<iostream> #include<cstdio> #include<cstdlib>using namespace std;const int maxn 4000;int p, n; bool inhash[maxn];int main() {freopen("447A.in", "r"…

面试突击 | Redis 如何从海量数据中查询出某一个 Key?视频版

作者 | 王磊面试突击 | 第 001 期1 考察知识点本题考察的知识点有以下几个&#xff1a;Keys 和 Scan 的区别Keys 查询的缺点Scan 如何使用&#xff1f;Scan 查询的特点2 解答思路 Keys 查询存在的问题Scan 的使用Scan 的特点3 Keys 使用相关 1&#xff09;Keys 用法如下2&#…

Linux debian设置主机不休眠教程

Debian系统设置主机不休眠&#xff0c;可以通过编辑Login Manager 的配置文件&#xff08;logind.conf&#xff09;来使配置生效。 1.打开终端&#xff0c;输入并执行以下命令&#xff1a; sudo vim /etc/systemd/logind.conf 2.打开文件后&#xff0c;将下面这行&#xff1…

面经 | 我是如何拿到阿里offer的?附面试题+视频

作者 | rhwayfunn来源 | http://dwz.win/2JK本文来自 rhwayfunn 本人自述&#xff1a;拿到阿里实习offer&#xff0c;经历了5次面试&#xff0c;其中4轮技术面&#xff0c;1轮HR面试。在这里分享一下自己的面试经验和学习总结。希望能够帮助更多的小伙伴。我本科毕业于中南大学…

SCOM 2012知识分享-9:配置警报解决状态

适应平台&#xff1a;System Center 2012 RTM/SP1-------------------------------------------------------------------------------------------------------------设置警报的解决状态在操作控制台中&#xff0c;请单击监视。单击任何视图&#xff0c;将显示警告&#xff0c…