动态规划(最长公共序列,最长上升序列)

在牛客网上刷面经的过程中,发现面试常问的两道题,这里记录下来,方便以后复习查看。

并分别在 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] 
    1、if P1[n]==P2[n],则 dp[n][n]=dp[n-1][n-1] + 1
    2、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)
        1、dp[0] = 1 
        2、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}好! 
        1、我们维护一个dp数组, dp[i]表示P[0..i]这个长度为i+1的序列 LIS最小值
        2、利用二分查找找到位置,并插入之 
        3、最后结果即为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;
}

 

posted on 2019-09-02 11:13  Magic_chao  阅读(532)  评论(0编辑  收藏  举报

导航