当前位置: 首页 > news >正文

动态规划算法

动态规划算法的核心思想是将复杂的问题拆解成子类问题,采用二维数组的方法模拟网格单元进行处理。如下所示:

000000...
0
0
0
0
...

通过上面的表格可以看到有两种区域,分别使用红色和绿色进行表示,红色表示新增的区域,而且该域内的值都是0;绿色区域表示实际的需要进行动态规划的区域。从上面的表格左上角开始,行、列所以你都是从0开始。

要理解动态规划算法,核心有两点:

  1. 动态规划算法是一个优化问题,那么上图中的绿色区域中的值应该就是要优化的值或者与之相关的值,即首先要搞明白我们要求什么最优解。举个例子背包问题中的绿色区域某个行列对应的网格的值就是对应的背包最大价值;最长公共子串问题,则需要遍历所有的网格单元求解最大值才能找到对应的最优解。
  2. 动态规划算法的一个思想就是将问题拆解为子问题与当前行列的问题进行求解。举个大家都知道的例子,求解最长公共子串问题可以拆分为不包含当列对应的字母区域的长度与这两个字母是否等的组合问题。

下面将我实现的一些动态规划算法写到下面,供大家参考理解。

#include <string>
#include <iostream>
#include <vector>

using namespace std;
//using namepsace std::literals
//使用动态规划算法实现两个字符串最长子串的长度
/*
 * 用例设计
 * 1. 没有任何公共子串
 * 2.仅包含一个公共子串
 * 3.公共子串在头部
 * 4.公共子串在尾部
 * 5.公共子串在中间
 * 6.仅包含一个或者多个字符长度的公共子串
 * 7.两个字符串完全相同
 * 8.包含两段不同长度的公共子串
 */
int longetsSubstringLength(string str1, string str2)
{
    int m = str1.length(); //求解第一个字符串的长度
    int n = str2.length(); //求解第二个字符串的长度

    vector<vector<int>> dp(m+1, vector<int>(n+1, 0));  //这里进行一个初始化,生成一个二维数组,形成动态规划特有的网格

    //进行双层遍历,遵从自底向上的策略,dp[0][x]的值都是0,dp[x][0]的值也都是0,网格单元的索引是从dp[1][1]开始的,dp[0][x]与
    //dp[x][0]都是默认值0
    for(int i = 1; i <= m; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            //如果该位置字符相等,那么就要获取其上一级的最大公共子串的值,即dp[i-1][j-1],如果i为1,那么就是dp[0][j-1];
            //如果j为1,那么就是dp[i-1][0],这些值都是0
            //如果这两个字符相等,那么需要获取它的左上角的值,取得该值后进行加1操作
            if(str1[i-1] == str2[j-1])
            {
                dp[i][j] = dp[i-1][j-1] + 1;
            }
            //如果不相等,则需要dp[i][j]的值等于dp[i-1][j-1]
            else{
                dp[i][j] = 0;
            }
        }
    }



    int maxNumber = 0;
    for(int i = 0; i <= m; i++)
    {
        for(int j = 0; j <= n; j++)
        {
            cout<<dp[i][j]<<"  ";
            if(dp[i][j] > maxNumber)
                maxNumber = dp[i][j];
        }
        cout<<endl;
    }
    return maxNumber;
}

//两个字符串最长公共子串,返回的不是长度而是一个字符串,测试用同上
string longestSubstring(string str1, string str2)
{
    int m = str1.length();
    int n = str2.length();

    int endIndex = 0;  //公共字符串的最后一位
    int maxLength = 0;  //字符串最大长度<

    vector<vector<int>> dp(m+1, vector<int>(n+1, 0));  //初始化二维数组

    //动态规划算法,算法思想如下,问题分解为不包含这个字符串的字符串的最大公共字符串长度求解,每个网格内的数字的含义是
    //若是相同的字符串则从左上角加一操作;若该位置两个字符不相等,则将该单元格数字设置为0,表示该位置的最长公共子串的长度为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] = dp[i-1][j-1] + 1;
                if(dp[i][j] > maxLength)
                {
                    maxLength = dp[i][j];
                    endIndex = i;  //设置最后一个索引
                }
            }
            //如果不相等,则设置为0
            else
            {
                dp[i][j] = 0;
            }
        }
    }
    int maxNumber = 0;
    for(int i = 0; i <= m; i++)
    {
        for(int j = 0; j <= n; j++)
        {
            cout<<dp[i][j]<<"  ";
            if(dp[i][j] > maxNumber)
                maxNumber = dp[i][j];
        }
        cout<<endl;
    }
    cout <<__FUNCTION__<<" maxLength = "<<maxLength<<" endIndex = "<<endIndex <<endl;
    if(maxLength == 0)
        return "";
    string str = str1.substr(endIndex-maxLength,maxLength);
    return str;
}

//获取两个字符串最长公共子序列的长度
/*
 ****************************************************
 *一.测试用例
 *1.空字符串返回0
 *2.没有公共序列的字符串
 *3.仅有一个公共序列的情况,分别位于头部,中间和尾部
 *4.包含多个相同字符串的情况,位置分别位于头部,中间和尾部
 *5.两个字符串完全相同
 */
int longestCommonSequnenceLength(string str1, string str2)
{
    int m = str1.length();
    int n = str2.length();
    if((m == 0) ||(n == 0))
        return 0;

    vector<vector<int>> dp(m+1, vector<int>(n+1, 0));  //创建二维数组,用于表示背包问题的网格

    for(int i = 1; i <= m ; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            //分解问题为不包含这两个字母的块的公共序列长度,和包含这两个字母的情况,这是一种组合
            //如果dp[i-1][j-1]为当前网格左上角的数值,它的含义是不包含这两个字符的情况下公共序列的长度
            //在前面的前提下,如果这两个字母相等,则需要在前面的左上角网格的基础上进行加1操作
            //如果两个字母不相等,这时候有两种情况,一种是在左上角的网格基础上只包含一个字母的情况,即dp[i][j-1], dp[i-1][j],判断这两个网格哪个大就选大的
            if(str1[i-1] == str2[j-1])
            {
                dp[i][j] = dp[i-1][j-1] + 1;
            }
            else
            {
                dp[i][j] = max(dp[i][j-1], dp[i-1][j]);
            }

        }
    }
    return dp[m][n];
}
//删除一个字符串中相同的字符
string remveSameCharacterInStr(string str)
{
    vector<char> vchar;
    int m = str.length();
    for(int i = 0; i < m; i++)
    {
        int n = vchar.size();
        int j;
        for(j = 0; j < n; j++)
        {
            if(str[i] == vchar.at(j))
                break;
        }
        if(j == n)
            vchar.push_back(str[i]);
    }
    vchar.push_back(0);
    string str1 =  vchar.data();
    return str1;
}
//求两个字符串有多少个相同的字符
int getSameCharacterLength(string str1, string str2)
{
    string newStr1 = remveSameCharacterInStr(str1);
    string newStr2 = remveSameCharacterInStr(str2);
    int m = newStr1.length();
    int n = newStr2.length();
    int number = 0;

    for(int i = 0; i < m; i++)
    {
        for(int j = 0; j < n; j++)
        {
            if(newStr1[i] == newStr2[j])
            {
                number++;
                break;
            }
        }
    }
    return number;

}

int main(int argc, char *argv[])
{
    int length = longetsSubstringLength("11333344444444", "111115555444444");
    cout <<" length = "<<length <<endl;
    string substr = longestSubstring("61333344444444", "611155554");
    cout <<" substr = "<<substr<<endl;
    int len = longestCommonSequnenceLength("1fcb", "1fcb");
    cout<<" len = "<<len<<endl;
    string str = remveSameCharacterInStr("121");
    cout<<"str = "<< str<<str.length()<<endl;
    int sameLen = getSameCharacterLength("aaaaaab","aaaabbb");
    cout<<"sameLen = "<<sameLen<<endl;
    return 0;
}

相关文章:

  • 探索ELK 的魅力
  • 原型模式详解(Java)
  • Nginx location 和 proxy_pass 配置详解
  • [Python 数据科学] Python 的良好编程规范与 logging 的使用
  • 如何下载AndroidStudio的依赖的 jar,arr文件到本地
  • 网络通信的基石:深入理解 TCP/IP 协议栈与 TCP/UDP 协议
  • Linux命令 ----操作命令
  • 2.14寒假
  • Baklib知识中台构建企业智能运营核心架构
  • 基于 openEuler 构建 LVS-DR 群集
  • 《玩转AI大模型:从入门到创新实践》(9)第七章 AI职业地图:从使用者到创造者
  • k8s集群搭建参考(by lqw)
  • DeepSeek处理自有业务的案例:让AI给你写一份小众编辑器(EverEdit)的语法着色文件
  • 给你一个三维numpy,形状为n*120*140,这里n<30,在其第一位维度n上扩展,将其扩展到30,扩展的部分全部设置为零
  • LLM:BERT or BART 之BART
  • 机器学习之AAE(Adversarial Autoencoder,对抗自编码器)生成数据样本
  • Jenkins项目CICD流程
  • Git GUI设置中文的方法及使用
  • 解决DeepSeek服务器繁忙问题
  • c++TinML转html
  • 微信做模板下载网站/怎样做企业推广
  • 四川省城乡建设厅官方网站/百度账号登录官网
  • 基础微网站开发口碑好/百度seo刷排名工具
  • 优化设计练习册/长沙正规seo优化价格
  • 南山商城网站建设哪家公司靠谱/百度指数趋势
  • 二手车网站开发PPT/手机关键词点击排名软件