最长上升子序列
2015-09-27 21:18
246 查看
算法在编程之美上有比较全面的介绍,第一种算法:
时间复杂度O(n2)O(n^2)
//假设在前i个元素中,最长的递增子序列长度为LIS[i]
//LIS[i+1] = max{1,LIS[k]+1},if for k<=i LIS[i+1]>LIS[k]
//总的时间复杂度为o(n2)
第二种做法,关键是增加一个记录数组,maxV[i]记录长度为i的最长上升子序列的最大值的最小值。
时间复杂度也是O(n2)O(n^2)。
第三种算法, 因为存在
时间复杂度O(n2)O(n^2)
//假设在前i个元素中,最长的递增子序列长度为LIS[i]
//LIS[i+1] = max{1,LIS[k]+1},if for k<=i LIS[i+1]>LIS[k]
//总的时间复杂度为o(n2)
int LIS2(vector<int>&arr){ vector<int> dp(arr.size(),0); //时间复杂度O(n2) for(int i=0;i<arr.size();++i){ for(int j=0;j<i;++j){ if(arr[i] > arr[j] && dp[j] + 1 > dp[i] ){ dp[i] = dp[j]+1; } } } //时间复杂度 O(n) int max_val =0; for(int i=0;i<dp.size();++i){ if(dp[i]>max_val) max_val = dp[i]; } return max_val; }
第二种做法,关键是增加一个记录数组,maxV[i]记录长度为i的最长上升子序列的最大值的最小值。
时间复杂度也是O(n2)O(n^2)。
//长度为1的递增子序列最大元素最小值为MaxV[1] //长度为2的递增子序列最大元素最小值为MaxV[2] //我们希望找到前i个元素中的一个递增子序列,使得这个递增子序列的最大元素比array[i+1]小,且长度尽量长。 int LIS(vector<int>& arr) { int currentLength = 1; vector<int> maxV; //maxV[i]表示长度为i的最长递增子序列最大值的最小值 maxV.push_back( ~(1<<31)+1);//最小值 maxV.push_back(arr[0]); //初始化长度为1时最大值的最小值为第一个元素 vector<int> dp(arr.size(),1);//dp[i]记录arr中1到i位中的lis的最长长度 int len = 1;// LIS长度 for(int i = 1; i < arr.size(); ++i) { int j; for(j= len;j>=0;--j){ if(arr[i]>maxV[j]){ //长度逐渐减小,因为希望尽可能长 dp[i] = j+1; //更新lis的长度 break; } } if(dp[i] > len)//表明最长上升序列长度增加了,即刚才在j=len时就退出了 { ++len; maxV.push_back(arr[i]); //maxV[++len]= arr[i]; }else //表明需要替换以前的值 { maxV[j+1] = arr[i]; } } return len; };
第三种算法, 因为存在
i<j则
maxV[i]<maxV[j], 所以可以采用二分法加速,时间复杂度为O(nlogn)O(nlogn)
// write your code here cpp #include<iostream> #include<vector> using namespace std; #define LOCAL //返回比x小的最大的数值的下标 int BinSearch(vector<int>& arr, int x) { int left = 0, right = arr.size()-1; int mid; while(left < right -1) { mid = (left + right) / 2; if(arr[mid] < x) { left = mid ; }else { right = mid-1; } } if(arr[right]<x) return right; return left; }; int LIS(vector<int>& arr) { int currentLength = 1; vector<int> maxV; //maxV[i]表示长度为i的最长递增子序列最大值的最小值 maxV.push_back( ~(1<<31)+1);//最小值 maxV.push_back(arr[0]); //初始化长度为1时最大值的最小值为第一个元素 vector<int> dp(arr.size(),1);//dp[i]记录arr中1到i位中的lis的最长长度 int len = 1;// LIS长度 for(int i = 1; i < arr.size(); ++i) { int j; //将这里换成二分可以降低时间复杂度 j = BinSearch(maxV,arr[i]);//返回比当前值arr[i]小长度的下标 dp[i] = j+1; if(dp[i] > len)//表明最长上升序列长度增加了,即刚才在j=len时就退出了 { ++len; maxV.push_back(arr[i]); //maxV[++len]= arr[i]; }else //表明需要替换以前的值 { maxV[j+1] = arr[i]; } } return len; }; int main(){ #ifdef LOCAL freopen("in.txt","r",stdin); #endif int n; while(cin>>n){ int tmp; vector<int> arr; while(n--){ cin>>tmp; arr.push_back(tmp); } cout<<LIS(arr)<<endl; } return 0; }
相关文章推荐
- java SE复习笔记49
- OCP-V13-010
- LINUX下C语言编程基础
- 白盒测试与黑盒测试
- 谷歌:已 Root 的设备不能使用 Android Pay
- java SE复习笔记48
- 将博客搬至CSDN
- 树木 - 风区 Tree - Wind Zones
- Exploiting Web application vulnerabilities
- 数据结构之树
- 2015迎国庆互联网趋势报告
- python list
- Android动画开发——Animation动画效果
- 软件工程之需求分析
- OCP-V13-009
- Playing with cubes II
- TSM-Install
- 服务器与客户端(2):多线程
- sql 2005 应用经验技巧与备忘
- java SE复习笔记47