动态规划(最长公共序列,最长上升序列)
在牛客网上刷面经的过程中,发现面试常问的两道题,这里记录下来,方便以后复习查看。
#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; }
非学无以广才,非志无以成学! 【Magic_chao】
posted on 2019-09-02 11:13 Magic_chao 阅读(533) 评论(0) 编辑 收藏 举报