值最大子串,最长无重复子串,最长无重复子序列,最长公共子串,最长公共子序列解法及代码

1.值最大子串

比如{5,-3,4,2}的最大子序列就是 {5,-3,4,2},它的和是8,达到最大;而 {5,-6,4,2}的最大子序列是{4,2},它的和是6。

思路:看子串和是否大于0,大于0继续加,小于0就从当前开始。

int maxSubSum(const vector<int> & arr,int &begin,int &end){
    int maxSum=0;
    int currSum=0;
    int newbegin=0;
    for(int i=0;i<arr.size();++i){
        currSum+=arr[i];
        if(currSum>maxSum){
            maxSum=currSum;
            begin=newbegin;
            end=i;
        }
        if(currSum<0){
            currSum=0;
            newbegin=i+1;
        }
    }
    return maxSum;
}

2. 最长无重复子串

子串(substring)——在字符串中是连续的

子序列(subsequence)——在字符串中可以不连续,也可以连续

思路:借助一个哈希表保存每个字符出现的位置

A)如果第i个字符之前没有出现过,那么f(i) = f(i-1)+1;

B)如果第i个字符之前出现过,记第i个字符和它上出现在字符串中的位置的距离,记为d。如果d>f(i-1),那么仍然有f(i) = f(i-1)+1;如果d<=f(i-1),则说明第i个字符上次出现在f(i-1)对应的不重复字符串之内,那么这时候更新 f(i) = d

class Solution {
public:
    int longestSubstringWithoutDuplication(const string& str) {
        int curLength = 0;
        int maxLength = 0;
        int* position = new int[26];
        for (int i = 0; i < 26; ++i)
            position[i] = -1;
        for (int i = 0; i < str.length(); ++i) {
            int prevIndex = position[str[i] - 'a'];
            if (prevIndex < 0 || i - prevIndex > curLength)
                ++curLength;
            else {
                if (curLength > maxLength)
                    maxLength = curLength;

                curLength = i - prevIndex;
            }
            position[str[i] - 'a'] = i;
        }
        if (curLength > maxLength)
            maxLength = curLength;
        delete[] position;
        return maxLength;
    }
};

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int m[256]={0},maxlen=0,left=0;
        for(int i=0;i<s.length();++i)
        {
            if(m[s[i]]==0 || m[s[i]]<left)   //从未出现过和未在当前滑动窗口内
                maxlen = max(maxlen,i-left+1);
            else 
            {
                left = m[s[i]];
            }
            m[s[i]] = i+1;
        }
        return maxlen;
    }
};

3.最长无重复子序列

思路:没用哈希表,只需要看之前是否出现过。也可以用个哈希表更快。

int lengthOfLongestSubstring(string s) {
        int max_len = 0, flag;
        for(int i = 0; i < s.length(); i++){
            flag = 1;
            for(int j = 0; j < i; j++){
                if(s[i] == s[j]){
                    flag = 0;
                    break;
                }
            }
            if(flag){
                max_len++;
            }
        }
        return max_len;
    }

4.最长公共子序列

子串(substring)——在字符串中是连续的

子序列(subsequence)——在字符串中可以不连续,也可以连续

示例:比如cnblogs和belong两个字符串,bo, bg, lg,blo,blog都在两个 字符串中出现过, 并且出现顺序一致,求最长公共子序列 为blog。最长公共子串为lo。

思路:

暴力解法
假设 m<n, 对于母串X,我们可以暴力找出2的m次方个子序列,然后依次在母串Y中匹配,算法的时间复杂度会达到指数级O(n∗2的m次)。显然,暴力求解不太适用于此类问题。
动态规划
假设Z=<z1,z2,⋯,zk>是X与Y的LCS, 我们观察到
如果Xm=Yn,则Zk=Xm=Yn,有Zk−1是Xm−1与Yn−1的LCS;
如果Xm≠Yn,则Zk是Xm与Yn−1的LCS,或者是Xm−1与Yn的LCS。
因此,求解LCS的问题则变成递归求解的两个子问题。但是,上述的递归求解的办法中,重复的子问题多,效率低下。改进的办法——用空间换时间,用数组保存中间状态,方便后面的计算。这就是动态规划(DP)的核心思想了。
DP求解LCS
用二维数组c[i][j]记录串x1x2⋯xi与y1y2⋯yj的LCS长度,则可得到状态转移方程

int lcs(String str1, String str2) {
    int len1 = str1.length();
    int len2 = str2.length();
    int **c = new int*[len1+1];
    for(int i=0;i<len1+1;++i)
        c[i]=new int[len2+1];
    for (int i = 0; i <= len1; i++) {
        for( int j = 0; j <= len2; j++) {
            if(i == 0 || j == 0) {
                c[i][j] = 0;
            } else if (str1[i-1] == str2[j-1]) {
                c[i][j] = c[i-1][j-1] + 1;
            } else {
                c[i][j] = max(c[i - 1][j], c[i][j - 1]);
            }
        }
    }
    return c[len1][len2];
}

5.最长公共子串

思路:同样可以用DP来解决。定义数组的存储含义对于后面推导转移方程显得尤为重要,糟糕的数组定义会导致异常繁杂的转移方程。考虑到子串的连续性,将二维数组c[i][j]用来记录具有这样特点的子串——结尾同时也为为串x1x2⋯xi与y1y2⋯yj的结尾——的长度。
得到转移方程:

最长公共子串的长度为 max(c[i,j]), i∈{1,⋯,m},j∈{1,⋯,n}。

int longsubstr(String str1, String str2) {
    int len1 = str1.length();
    int len2 = str2.length();
    int result = 0;     //记录最长公共子串长度
    int **c = new int*[len1+1];
    for(int i=0;i<len1+1;++i)
        c[i]=new int[len2+1];
    for (int i = 0; i <= len1; i++) {
        for( int j = 0; j <= len2; j++) {
            if(i == 0 || j == 0) {
                c[i][j] = 0;
            } else if (str1[i-1] == str2[j-1]) {
                c[i][j] = c[i-1][j-1] + 1;
                result = max(c[i][j], result);
            } else {
                c[i][j] = 0;
            }
        }
    }
    return result;
}

参考博客:

https://www.cnblogs.com/zhaogl/p/6364654.html

https://blog.csdn.net/u012102306/article/details/53184446

https://blog.csdn.net/wangdd_199326/article/details/76464333

猜你喜欢

转载自blog.csdn.net/qq_21997625/article/details/85101716
今日推荐