无重复字符的最长子串

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:

输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:

输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
  请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

 

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int maxlen = 0;
        int curlen = 0;
        unordered_map<char,int> charMap;

        for(int i = 0; i < s.size(); i++){
            if(charMap.find(s[i]) == charMap.end()){
                charMap[s[i]] = i+1;
                curlen += 1;
            }
            else{
                curlen = min(i+1 - charMap[s[i]], curlen+1);
                charMap[s[i]] = i+1;
            }
            maxlen = maxlen < curlen ? curlen : maxlen;
        }

        return maxlen;
    }
};

解题思路:
我是这么思考的:以 s[i] 结尾的子串跟以 s[i-1] 结尾的子串有什么关系?

假设我们已知以 s[i-1] 结尾的无重复字符最长子串的长度,那么对于以 s[i] 结尾的子串来说,无非就是两种可能:

1. s[i] 曾出现过

2. s[i] 未曾出现过

情况1简单啊,那就在前者长度的基础上+1呗

情况2我们要稍微讨论一下:

(1)如果 s[j] = s[k] = s[i],j < k < i,也就是说前面的子串出现过两次 s[i] 了,那么计算以 s[i] 为结尾的最长无重复字符子串长度时,我们肯定是拿 s[i] 跟s[k] 来计算,而不会拿 s[j]。这意味着我们可以用一个hashmap存储字符的位置,并且在每次出现重复字符的时候,更新hashmap。

(2)如果前面出现过 s[i],那我们计算长度的时候是不是直接 i - k 就好了呢?当然不是,因为 k 到 i 之间的这个子串可能还有其他字符的重复字符,比如: “abba”。

假设我们用 lastlen 和 curlen 分别记录以 s[i-1],s[i] 结尾的最长无重复字符子串的长度

那么 curlen = min(lastlen+1, i - k)

因为如果 k 到 i 之间的子串出现重复字符了,那么 i - k 肯定大于 lastlen + 1,此时我们要用 lastlen 来计算 curlen,而不能拿 i 和 k来计算

如果k 到 i 之间的子串没有出现重复字符,那么 i - k 会等于 lastlen + 1,所以取最小值是ok的。

 

posted @ 2020-04-02 18:24  jenningszheng  阅读(1921)  评论(0编辑  收藏  举报