LIS & LCS

《动态规划初步·各种子序列问题》,作者是Flower_pks.动态规划初步·各种子序列问题

最长上升子序列(LIS):
  • 元素不一定相邻
  • O(n^2)
  • dp[i]:到i元素为止的最长上升子序列长度,初始值为1;暴力枚举i之前的所有子串
data[N],booK[N];//记录数组
void out(int x){//输出最长子序列
    if(!x) return;
    out(book[x]);
    cout << data[x] << ' ';//回溯 输出答案
}

for(int i = 1; i <= n; i++){
    dp[i] = 1;
    book[i] = 0;
    for(int j = 1; j < i; j++){//枚举i之前的所有j
        //i元素之前小于他的j元素满足:dp[j] + 1 大于 当前最长上升子序列长
        //dp[1] - dp[n] 维护最大值
        if(data[j] < data[i] && dp[i] < dp[j] + 1) dp[i] = dp[j] + 1,book[i] = j;
    }
}

int ans = dp[1],pos = 1;
for(int i = 1; i <= n; i++){
    if(ans < dp[i]) ans = dp[i],pos = i;//记录最大值的索引
}
cout << ans << endl;
out(pos);
  • O(nogn):
//dp[i]表示长度为i的上升子序列的最小末尾元素
//当a[i] > dp[len] 时上升子序列长度 + 1,dp[++len] = a[i]
//else 二分搜索修改其它长度的上升子序列的最小末尾
	int len = 1;
	dp[1] = a[1];
	for(int i = 2; i <= n; i++){
		if(a[i] > dp[len]) dp[++len] = a[i];
		else{
			//二分更新最小末尾 
			int l = 1, r = len,mid;
			while(l < r){
				mid = (l + r) >> 1;
				if(dp[mid] >= a[i]) r = mid;
				else l = mid + 1;
			}
			dp[l] = min(a[i], dp[l]);//更新对应长度上升子序列的最小末尾 
		}
	} 
	cout << len; 
最长公共子序列(LCS)
//dp[i][j]:a串前i,b串前j个元素的最长公共子序列
//if(a[i] == b[j])dp[i][j] = max(dp[i][j],dp[i - 1][j - 1] + 1);
//else dp[i][j] = max(dp[i - 1][j],dp[i][j - 1]);

cin >> n >> m;//a b串长度
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= m; i++) cin >> b[i];
for(int i = 1; i <= n; i++){
	for(int j = 1; j <= m; j++){
            dp[i][j] = max(dp[i - 1][j],dp[i][j - 1]);
            if(a[i] == b[j]) dp[i][j] = max(dp[i][j],dp[i - 1][j - 1] + 1);
    }
}
cout << dp[n][m];
posted @ 2020-04-22 16:59  jimmy-cat  阅读(151)  评论(0编辑  收藏  举报