動態規劃(最長公共序列,最長上升序列)

在牛客網上刷面經的過程當中,發現面試常問的兩道題,這裏記錄下來,方便之後複習查看。ios

並分別在 poj  1458   2533   AC!面試

#include<iostream>
#include<cstring>
#include<cstdio>
#define N 1005
using namespace std;
int dp[N][N];

/*
    dp[i][j]表示 P1[1...i]與 P2[1...j]的最長公共子序列LCS 
    初始狀態:某一個排列爲空,那麼LCS確定爲0,故很容易推斷出 dp[0][1..n]=0, dp[1..n][0] 
    一、if P1[n]==P2[n],則 dp[n][n]=dp[n-1][n-1] + 1
    二、if P1[n]!=P2[n], 則 dp[n][n] = max(dp[n][n-1], dp[n-1][n]) 
    
    Tips: 
    爲了提升效率,採用自底向上計算的方法。
    也即先計算dp[1][1]... 最後計算dp[n][n],由於dp[n][n]確定要用到以前的狀態嘛
*/

int solve(string p1, string p2, int p1_len, int p2_len){
    for(int i=1;i<=p1_len;i++){
        for(int j=1;j<=p2_len;j++){
            if(p1[i-1]==p2[j-1]){
                dp[i][j] = dp[i-1][j-1] + 1;
            }else{
                dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
            }
        }
    }
    return dp[p1_len][p2_len];
}
int main(){
    string p1, p2;
    while(cin>>p1>>p2){
        memset(dp, 0, sizeof(dp));
        int p1_len = p1.length();
        int p2_len = p2.length();
        cout<<solve(p1, p2, p1_len, p2_len)<<endl;
    }
    return 0;
}

 

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define N 1005
using namespace std;
int p1[N];
int n; 
int dp[N];
/*
    dp[i]表示 P[0...i] 的最長上升子序列 LIS 代碼中solve_1
    方法一 : 直接dp,O(n^2)
        一、dp[0] = 1 
        二、dp[i] = max(dp[i], dp[j]) + 1, 0<=j<i, P[i]>P[j](由於只有大於纔是上升的序列) 
    
    方法二 :貪心 + 二分,O(nlogn) 代碼中solve_2 
        貪心:對於固定某一長度LIS而言,最後一個數字越小,越有可能添加新元素 
              如長度爲2的LIS{1,2}比{1,3}好! 
        一、咱們維護一個dp數組, dp[i]表示P[0..i]這個長度爲i+1的序列 LIS最小值
        二、利用二分查找找到位置,並插入之 
        三、最後結果即爲dp數組的長度 
*/
int solve_1(int p1[], int p1_len){
    int ans = 0;
    for(int i=0;i<p1_len;i++){
        dp[i]=1;
    }
    for(int i=0;i<p1_len;i++){
        for(int j=0;j<i;j++){
            if(p1[i]>p1[j])
                dp[i] = max(dp[i], dp[j]+1);
        }
        ans = max(ans, dp[i]);
    }
    return ans;
}

int solve_2(int p1[], int p1_len){
    int pos = 0;
    dp[0]=p1[0];
    for(int i=1;i<p1_len;i++){
        if(p1[i]>dp[pos]){
            dp[++pos] = p1[i];
        }else{
            int *idx = lower_bound(dp, dp+pos+1, p1[i]);
            //cout<<*idx<<endl;
            dp[idx-dp] = p1[i];
        }
    }
    return pos+1;
}
int main(){ 
    cin>>n;
    for(int i=0;i<n;i++){
        int m;cin>>m;
        p1[i]=m;
    }
    //cout<<solve_1(p1, n)<<endl;
    cout<<solve_2(p1, n)<<endl;
    return 0;
}
相關文章
相關標籤/搜索