LIS初级推算(最长上升子序列问题)
所谓LIS,就是Longest Increasing Subsequence问题
注意,子序列不一定是连续的,举个例子:对于序列10,9,2,3,5,4,7,9,101,18,其中的LIS就是2,3,5,7,9,18(或者2,3,5,7,9,101)
那么就出现另一个要注意的地方了:LIS自身不一定只有一个,但是LIS.length()一定是固定的(很容易反证对吧)
【鉴于我是第一次研究LIS,所以自己分析出来的dp可能会很水不高级orz】
那不如我们就从上面那个例子开始吧~
vector<int> nums = {10,9,2,3,5,4,7,9,101,18}
初始:dp[0] = 1 因为就只有它自己,同时我们指定所返回的数如果其前面没有比他更小的就返回自己的位置
第i个数 | nums[i] |
上一个比nums[i]小的数的位置 |
dp[i] | 序列 |
0 | 10 | 0 | 1 | 10 |
1 | 9 | 1 | 1 | 9 |
2 | 2 | 2 | 1 | 2 |
3 | 3 | 2 | 2 | 2,3 |
4 | 5 | 3 | 3 | 2,3,5 |
5 | 4 | 2 | 3 | 2,3,4 |
6 | 7 | 4 | 4 | 2,3,5,7 |
7 | 9 | 6 | 5 | 2,3,5,7,9 |
8 | 101 | 7 | 6 | 2,3,5,7,9,101 |
9 | 18 | 7 | 6 | 2,3,5,7,9,18 |
注意:根据“贪心”的我们的需求,我们在寻找上一个比nums[i]小的数的位置时保证所找到的dp对应数字最大
那么我们就需要一个函数,返回上一个比nums[i]小的数的位置
1 vector<int> dp(10001,0);
2 int find_last_less_place(int now,vector<int>& nums,int pos)
3 {
4 int max_dp_place = pos;
5 for (int i = pos - 1; i >= 0; i--)
6 {
7 if(nums[i] < now)
8 {
9 if(dp[i] > dp[max_dp_place])
10 max_dp_place = i;
11 }
12 }
13 return max_dp_place;
14 }
然后我们就可以进行总的处理啦
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //最长上升子序列 2 int lengthOfLIS(vector<int>& nums) 3 { 4 if (nums.size() == 0) 5 return 0; 6 if (nums.size() == 1) 7 return 1; 8 9 int MAX = -1; 10 dp[0] = 1; 11 12 cout << "last = NaN" << " now_place = 0" << " now is = " << nums[0] << " dp[i] = " << 1 << endl; 13 for (int i = 1; i < nums.size(); ++i) 14 { 15 int last_place = find_last_less_place(nums[i],nums,i); 16 cout << "last = " << last_place << " now_place = " << i << " now is = " << nums[i] << " "; 17 if(last_place == i) 18 dp[i] = 1; 19 else 20 dp[i] = dp[last_place] + 1; 21 cout << "dp[i] = " << dp[i] << endl; 22 MAX = max(MAX,dp[i]); 23 } 24 return MAX; 25 }
现在的问题就是这个算法的复杂度为O(n^2),下一次更新就是我学成O(nlogn)之时~顺便还有LICS,LCS等问题
大家和我一起加油呀!!!!!!