该问题旨在求解序列中最长子序列,子序列不同于子串,没有连续性要求,显然最长子序列具备最优子结构性质。
如何获取递推表达式呢?
(1)状态是什么?
序列的长度,在序列长度由1~(1~len)变化过程中,最长子序列的长度怎么随之变化呢?
(2)如何表示第i个状态和第i-1个状态之间的关系?
opt(i)表示下标为0~i的序列的最长子序列,那么opt(i-1)表示下标为0~i-1的序列的最长子序列.
opt(i)的大小取决于nums[i]与nums[0~i-1]的大小关系,可以写出递推表达式:
opt[i] = max(opt[j] +1) if j for any one j satisfy nums[i] > nums[j]
opt[i] = 1 if j for all j statisfy nums[i] < nums[j]
// O(n^2)intfindLengthLIS(vector<int>&nums){int len = nums.size();if(len ==0){return0;}
vector<int>opt(len);
opt[0]=1;for(int i =1; i < len; i++){int re =1;for(int j =0; j < i; j++){if( nums[i]> nums[j]){
re =max(re,opt[j]+1);}}
opt[i]= re;}int max_len =0;for(auto e: opt){
max_len =max(max_len,e);}return max_len;}
如何进阶?换种思路:纸牌游戏,图片很形象,相信小时候玩过的一看就懂。
//O(nlogn)intlengthOfLIS(vector<int>& nums){int len = nums.size();
vector<int>heap(len);int piles =0;// 对每个num进行操作:替换掉原有堆,还是成为新的堆首for(int i =0; i < len; i++){//对所有堆进行二分查找int left =0,right = piles;while(left < right){int mid =(left + right)/2;if(heap[mid]>= nums[i])//往左边查{
right = mid;}elseif(heap[mid]< nums[i])//往右边查{
left = mid +1;}}if(left == piles)//当前牌是heap中最大的{
piles ++;}
heap[left]= nums[i];}return piles;}