zoukankan      html  css  js  c++  java
  • [DP]最长公共子串

    题目

    给定两个字符串str1和str2, 长度分别稳M和N,返回两个字符串的最长公共子串

    解法一

    这是一道经典的动态规划题,可以用M*N的二维dp数组求解.dp[i][j]代表以str1[i]和str2[j]当做公共子串结尾的情况下,公共子串能有多长.然后分析可以发现dp[i][j]只与dp[i- 1][j - 1]有关:当str1[i] 和str2[j]相等的时候, dp[i][j] = dp[i - 1][j - 1] + 1;当它们不相等的时候,dp[i][j] = 0.获得dp数组之后要获得最长公共子串只需要找到数组中最大的值,其值代表最长子串的长度,其所在的索引代表了子串在原字符串中结束的位置.

    代码

    先获取dp数组,然后通过dp数组得到最长公共子串

    //最长公共子串的dp数组
    vector<vector<int> > getdp1(string str1, string str2) {
        vector<vector<int> > dp(str1.length(), vector<int>(str2.length()));
        if (str1.length() == 0 || str2.length() == 0)
            return dp;
        dp[0][0] = str1[0] == str2[0] ? 1 : 0;
        for (int i = 1; i < int(str1.length()); i ++)
            dp[i][0] = str1[i] == str2[0] ? 1 : 0;
        for (int j = 1; j < int(str2.length()); j ++)
            dp[0][j] = str2[j] == str1[0] ? 1 : 0;
    
        for (int i = 1; i < int(str1.length()); i ++) {
            for (int j = 1; j < int(str2.length()); j ++) {
                if (str1[i] == str2[j])
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                else
                    dp[i][j] = 0;
            }
        }
        return dp;
    }
    
    // 最长公共子串的解法一
    string lcst1(string str1, string str2) {
        string res = "";
        if (int(str1.length()) == 0 || int(str2.length()) == 0)
            return res;
        vector<vector<int> > dp = getdp1(str1, str2);
        int maxNum = 0;
        int maxIndex;
        for (int i = 0; i < int(dp.size()); i ++) { // 遍历dp矩阵找到最大值
            for (int j = 0; j < int(dp[0].size()); j ++)
                if (dp[i][j] > maxNum) {
                    maxNum = dp[i][j];
                    maxIndex = i;
                }
        }
    
        res = str1.substr(maxIndex - maxNum + 1, maxNum);
        return res;
    }
    

    解法二

    上面这种解法需要的时间复杂度和空间复杂度都是O(M* N).下面提供一种空间复杂度为O(1)的解法

    代码

    //最长公共子串解法二
    string lcst2(string str1, string str2) {
        string res = "";
        if (int(str1.length()) == 0 || int(str2.length()) == 0)
            return res;
    
        int maxNum = 0; //记录最大值
        int maxindex = -1; //记录最大值的索引
        int tmpNum; //记录当前值,如果大于最大值就更新
        int i = int(str1.length()) - 1;
        int j = int(str2.length()) - 1;
        for (j; j >= 0; j --) { // 斜线先向左移动
            tmpNum = 0;
            for (int tmp = 0; tmp < int(str2.length()) - j; tmp ++){
                if (str1[tmp] == str2[j + tmp]) {
                    tmpNum = tmpNum == 0 ? 1 : tmpNum + 1;
                } else
                    tmpNum = 0;
                if (tmpNum > maxNum) {
                    maxNum = tmpNum;
                    maxindex = j + tmp;
                }
            }
        }
    
        bool triangleUpFlag = true; //maxindex 在通过斜线计算的时候属于上三角的flag
        for (i; i > 0; i --) { //列移到最左边之后再向下移动
            tmpNum = 0;
            for (int tmp = 0; tmp < int(str1.length()) - i; tmp ++) {
                if (str2[tmp] == str1[i + tmp])
                    tmpNum = tmpNum == 0 ? 1 : tmpNum + 1;
                else
                    tmpNum == 0;
                if (tmpNum > maxNum) {
                    maxNum = tmpNum;
                    triangleUpFlag = false;
                    maxindex = i + tmp;
                }
            }
        }
    
        cout<<maxindex<<" "<<maxNum<<" "<<triangleUpFlag<<endl;
        res = triangleUpFlag == true ? str2.substr(maxindex - maxNum + 1, maxNum) : str1.substr(maxindex - maxNum + 1, maxNum);
        return res;
    }
    
    int main()
    {
        string str1 = "1AB2345CD";
        string str2 = "12345EF";
        //string str1 = "abcde";
        //string str2 = "bebcd";
        cout<<lcst2(str1, str2)<<endl; //输出2345
        return 0;
    }
    
  • 相关阅读:
    解决ios手机页面overflow scroll滑动很卡的问题
    响应式网页设计:rem、em设置网页字体大小自适应
    linq 和lambda查询
    单元测试的学习
    各种仓储模式的学习
    ref 微软官网
    泛型 学习
    aop 和castle 的一些 学习文章
    autofac 的好博文
    json 序列化和反序列化的3个方法
  • 原文地址:https://www.cnblogs.com/mooba/p/7473553.html
Copyright © 2011-2022 走看看