动态规划

概念

动态规划:先解决子问题,再逐步解决大问题。

动态规划和贪心算法:都是自底向上分析问题的算法,区别在于动态规划着眼于全局最优解,而贪心算法着眼于局部最优解

动态规划和分治法:动态规划是自底向上分析问题,先解决小问题再解决大问题,而分治法是自顶向下分析问题,先拆分大问题为小问题,解决了小问题,大问题也就被解决了。

查找最长公共子串

题目描述 力扣 718 最长重复子数组

给两个整数数组 A 和 B ,返回两个数组中公共的、长度最长的子数组的长度。
在这里插入图片描述

题目解析

经典的背包问题

首先我们来画一个背包网格,单元格中的值代表了公共子串的长度,横纵坐标分别表示两个数组的各个元素

  • 如果两个元素的值相同,那么就在前一步(也就是d p[i-1][j-1] )的基础上 +1(前一步代表有多少公共子串)
  • 如果两个元素的值不相同,则为0(说明公共子串断开了)
  • 最终结果为网格中最大的值,不一定是最后一个格中的值

伪代码实现

class Solution {
public:
    int findLength(vector<int>& A, vector<int>& B) {
        int n1 = A.size(), n2 = B.size();
        vector<vector<int>> dp(n1+1, vector<int>(n2+1, 0));//初始化所有网格为0,图中只有5行5列,其实还隐藏了最上面和最左边的元素,因为都是0,不用计算,但必须要初始化
        int res = 0;//记录网格中的最大值

        for(int i=1; i<=n1; i++)//dp隐藏了第0行第0列
        {
            for(int j=1; j<=n2; j++)
            {
                if(A[i-1]==B[j-1]) 
                    dp[i][j] = dp[i-1][j-1] + 1;
                else
                    dp[i][j] = 0;

                res=max(ans,dp[i][j]);//更新最大值
            }
        }
        return res;
    }
};

查找最长公共子序列

先说明两种题目的不同之处

  • 最长公共子串,子串在原字符串中必须两两相邻;
  • 最长公共子序列,子序列在原字符串中不必两两相邻,只需按原顺序排列即可。
题目描述 1143 最长公共子序列

给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
在这里插入图片描述
可以自己先画一个网格,思考一下各个单元格之间的关系。

题目解析

首先我们来画一个网格,单元格中的值代表了公共子序列的长度,横纵坐标分别表示两个字符串的各个字母

  • 如果两个字母相同,那么就在前一步(也就是d p[i-1][j-1] )的基础上 +1(前一步代表有多少公共子串)
  • 如果两个字母不相同,则为上面和左边位置中最大的那个值

伪代码实现

class Solution {
public:
    int longestCommonSubsequence(string text1, string text2) {
        int m=text1.length(),n=text2.length();
        vector<vector<int>> dp(m+1,vector<int>(n+1,0));
        int res=0;

        for(int i=1;i<=m;i++)
            for(int j=1;j<=n;j++)
            {
                if(text1[i-1]==text2[j-1])
                    dp[i][j]=dp[i-1][j-1]+1;
                else
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1]);

                res=max(res,dp[i][j]);
            }  
            return res;
    }
};

相似例题 永不相交的线

查找好的公共子序列

题目描述

输入一个字符串s 找出最长的子字符串满足1807的顺序,好的子序列就是指按照1807的顺序排列的子序列,1807可以重复。

例如
输入:1180011111877007
输出:11
其中好的最长子序列为11111118007

题目解析

同样先画一个网格,单元格中的值代表了好的公共子序列的长度,横纵坐标分别表示两个字符串的各个数字

  • 如果两个数字不相同,则为上面和左边位置中最大的那个值
  • 如果两个数字相同,那么就在上面和左边位置中最大值的基础上+1

代码实现

#include<iostream>
#include<string>
#include<vector>
using namespace std;

int GetMaxLen(string str1,string str2)
{
	int m=str1.length();
	int n=str2.length();
	vector<vector<int>> dp(m+1,vector<int>(n+1,0));
	int result=0;

	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++)
		{
			if(str1[i-1]==str2[j-1])
				dp[i][j]=max(dp[i-1][j],dp[i][j-1])+1;
			else
				dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
				
			result=max(result,dp[i][j]);
		}
	return result;
}

int main()
{
	string str1;
	string str2="1807";
	cin>>str1;

	int len=GetMaxLen(str1,str2);
	cout<<len<<endl;
	system("pause");
	return 0;
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值