面试题48:最长不含重复字符的连续子字符串

请从字符串中找出一个最长的不包含重复字符的连续子字符串,计算该最长连续子字符串长度。假设字符串只包含'a'~'z'的字符。例如在字符串"arabcacfr"中,最长连续子字符串为"acfr",长度为4。

解题思路

  这是一道基础的动态规划题,首先应该能想到用暴力法解决,然后再考虑是否能用动态规划来优化。

  • 暴力法(复杂度较高O(n^3))
  • 动态规划(从左到右,循环计算,降低复杂度)

上代码(C++香)

动态规划法

  状态转移方程比较复杂,首先用\(f(i)\)来表示以第i个字符结尾的不包含重复字符的子字符串的最长长度。初始化\(f(0) = 1\)

  • 如果第i个字符之前没出现过,那么\(f(i) = f(i - 1)+1\)
  • 如果第i个字符之前出现过,求出上次最近出现的位置k,并求出距离\(d=i-k\)
    • 如果\(d<=f(i-1)\),说明上次出现在\(f(i-1)\)对应的最长子字符串中,此时\(f(i)=d\)
    • 如果\(d>f(i-1)\),说明上次出现在\(f(i-1)\)对应的最长子字符串外,此时可令\(f(i)=f(i-1)+1\)
// 动态规划法
int longestSubstringWithOutDuplication(string str){
    int length = str.length();
    int states[length];

    // 初始化第一个数
    states[0] = 1;
    for(int i = 1; i < length; i++){
        // 找出上次最后出现str[i]的位置
        int k = -1;
        for(int j = 0; j < i; j++){
            if(str[j] == str[i])
                k = j;
        }
        // 如果str[i]之前没出现过
        if(k == -1)
            states[i] = states[i - 1] + 1;
        // 如果str[i]之前出现过
        // 获得出现距离d
        if(k != -1){
            int d = i - k;
            if(d <= states[i - 1])
                states[i] = d;
            else
                states[i] = states[i - 1] + 1;
        }
    }

    int maxN = -1;
    for(int i = 0; i < length; i++){
        if(states[i] > maxN)
            maxN = states[i];
        cout<<states[i]<<" ";
    }
    cout<<endl;
    return maxN;

}

int main(int argc, char* argv[])
{
    cout<<longestSubstringWithOutDuplication("arabcacfr");
    return 0;
}
posted @ 2020-08-20 17:41  程序员曾奈斯  阅读(570)  评论(0)    收藏  举报