【数据结构】剑指Offer——面试题48:最长不含重复字符的子字符串

  总觉得书上这题讲的怪怪的,所以将自己的思路写下来。

题目描述:

请从字符串中找出一个最长的不包含重复数字的子字符串,计算该最长子字符串的长度。假设字符串中仅包含 ‘a’~’z’ 之间的字符。例如,在字符串 “arabcacfr” 中,最长的不包含重复字符的子字符串是 “rabc” 或 “acfr”,所以应当输出 4。

分析:

  考虑使用动态规划法

  因为所有可能出现的字符是有限的,所以首先使用一个 字母哈希表来存储当前字母上一次字母出现的位置。也就是:

vector<int> last_pos(26,-1);

然后定义函数 dp[i] 表示以当前字母结尾(以当前字母作为子串最后的字母)的最长不含重复字符的子字符串。

  分为两种大情况进行讨论

  • 如果当前字符没有出现过

    这种情况很简单,只需要令 dp[i]=dp[i-1]+1 即可;

  • 如果当前字符出现过

    这种情况还需要再细分为两种情况:

    1. 如果当前字符的位置距离上一次出现的位置 小于等于 dp[i-1],则 dp[i]=d,其中 d 为当前位置和上一次出现的位置之间的距离。
    2. 如果当前字符的位置距离上一次出现的位置 大于 dp[i-1],则 dp[i]=dp[i-1]+1

  根据上面的思路,写出如下代码:

// 最长不含重复字符的子字符串
int longestSubstringWithoutDuplication(const string& str)
{
    if (str.empty())
        return 0;
    int len = str.length();
    vector<int> dp(len);
    dp[0] = 1;
    auto maxx = 1;
    // 建立一个字母哈希来保存当前的字母上一次的位置
    vector<int> last_pos(26,-1);    
    last_pos[str[0] - 'a'] = 0;
    for (auto i = 1; i < len; i++)
    {
        auto lastPos = last_pos[str[i] - 'a'];
        if (lastPos >= 0)
        {
            if ((i - lastPos) <= dp[i - 1])
                dp[i] = i - lastPos;
            else
                dp[i] = dp[i - 1] + 1;
        }
        else
            dp[i] = dp[i - 1] + 1;
        // 存下每个字母本次出现的位置
        last_pos[str[i] - 'a'] = i;
        maxx = max(maxx, dp[i]);
    }
    return maxx;
}

你可能感兴趣的:(数据结构)