最長上升子序列動態規劃

漫漫想想發表於2020-12-25

給出序列長度,輸入序列 求出最長上升子序列
使用動態規劃
將問題分解成為子問題
如果分解成n-1長度的子問題會出現無後效的問題 即就是前面計算的內容對後面還是會產生影響 不能完全分解成為獨立子問題
例如 1 2 5 3
n =1 最長為1
n =2 最長為2 flag1
n=3 最長為3 flag2
n=4
如果將其分解為n-1的子問題 這裡明顯會出現問題 n=4的答案是前面flag1 與flag2 中取最大值 即就是 n=4時取flag2+1

但是顯然我們知道 那是不正確的
這裡也給我們啟示如何去解決這樣的問題
這裡出現這樣的問題是因為我們無法解決無後效的原因 那既然有影響我們找出相應的影響因素
我們可以看出我們找出最長子序列是忽略了當前值是否小於前面以及求出的子問題的相應值 即就是我們沒有判斷 flag2 對應的n=3 時的 5是否小於當前n=4的3
如何解決 只需要遍歷一下前面的所有 找出比當前n對應的值小的 最長上升子序列長度+1 即可 還有細節思考的 就不多討論了

其實從前面的無後效性我們可以看出這個問題的子問題 不是線性 ,他是跳躍的 即 我們是在所有滿足條件的子序列中尋找最長序列
怎麼理解捏 就是當前這個問題是長度n 我們求解的其實n-1中滿足條件的上升子序列 然後找出其中滿足比n小的首要條件之後 中最長的一個序列 這個才是真正的子問題 也許可以從這個角度去理解這個問題
解決動態規劃有很多種方式 遞迴 遍歷
但是動態規劃的實質是什麼 才是我們知道使用這種方法的關鍵 這個可以通過練習掌握
避免重複運算 擁有最優子結構 還是其他 都需要我們練習理解

#include<iostream>
#include<algorithm>
using namespace std;
int stringLen=1010;
int nums[stringLen];
int maxlen[stringLen];
int main(){
         int n;
         for(int i=1;i<=n;i++){
         cin>>nums[i];
         maxlen[i]=1;
         }
         for(int i=2;i<=n;i++){
            for(int j=1;j<i;j++){
            if(nums[j]>nums[i]){
                   maxlen[i]=max(maxlen(i),maxlen[j]+1);
                 }
            }
         }
         cout<<*max_element(nums+1,nums+n+1)<<endl;       
        return 0;
}

這裡可以沒必要使用max_element()函式
可以增加一個max 來記錄最大值即可

java 版笨解決最長上升子序列

class Solution {
    public int lengthOfLIS(int[] nums) {
       int max=1;
       int[] maxlen=new int[nums.length];
       maxlen[0]=1;
       for(int i=1;i<nums.length;i++){
               maxlen[i]=1;
               for(int j=0;j<i;j++){
                   if(nums[j]<nums[i]){
                       maxlen[i]=Math.max(maxlen[i],maxlen[j]+1);
                   }
               }
               max=Math.max(max,maxlen[i]);
       }
     return max;
    }

}
這題我們也可以使用貪心+二分解決

相關文章