該問題旨在求解序列中最長子序列,子序列不同於子串,沒有連續性要求,顯然最長子序列具備最優子結構性質。
如何獲取遞推表達式呢?
(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;}