哈希+滑动窗口

  • 是否重复->哈希,最长->双指针计算长度
  • 当出现重复时,子字符串的从上一个字符的下一位开始计算长度,用哈希保留字符和上一次出现的索引
  • 注意最后字符不重复时计算长度为end-start+1,最后字符重复时字符长度为end-start
#include <unordered_map>
class Solution {
  public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param s string字符串
     * @return int整型
     */
    int lengthOfLongestSubstring(string s) {
        // write code here

        int max_length = 0, length = 0;
        int start = 0, end = 0;
        unordered_map<char, int> ump;
        for (int i = 0; i < s.size(); i++) {
            if (ump.find(s[i]) == ump.end()
                    || ump[s[i]] == -1) {
                //不存在
                ump[s[i]] = i;
                end = i;
                if(i==s.size()-1)
                {
                    if(max_length<end-start+1)
                    {
                        max_length=end-start+1;
                    }
                }
            } else {
                //存在
                //计算长度
                end = i;
                length = end - start;
                if (max_length < length) {
                    max_length = length;
                }
                int j = ump[s[i]]; //前面的索引
                for (int k = start; k <= j; k++) {
                    ump[s[k]] = -1;
                }
                start = j + 1;

                ump[s[i]] = i;

            }

        }
        return max_length;
    }
};

更简洁的写法

  • 创建mp[i]的初始值是0
  • 每个数统一处理先加1再判断是否重复
  • 巧妙的遍历直到重复元素
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char, int> mp; 
        int res = 0;
        for(int left = 0, right = 0; right < s.length(); right++){ 
            mp[s[right]]++; 
            while(mp[s[right]] > 1) 
                mp[s[left++]]--; 
            res = max(res, right - left + 1); 
        }
        return res;
    }
};

哈希+动态规划

  • 本质是一样的
  • 区别在于1.dp保存结果 2. 最大值的计算,滑动窗口是移动一格知道符合条件,这里是直接保存索引
class Solution {
  public:
    int lengthOfLongestSubstring(string s) {
        //哈希表记录窗口内非重复的字符及其下标
        unordered_map<char, int> mp;
        int res = 0;
        //dp[i]表示以下标i结尾的字符串最长不含重复子串的长度
        vector<int> dp = vector<int>(s.length() + 1, 0);
        for (int i = 1; i <= s.length(); i++) {
            //哈希表中没有,说明不重复
            if (mp.find(s[i - 1]) == mp.end())
                //前一个加1
                dp[i] = dp[i - 1] + 1;
            //遇到重复字符
            else
                dp[i] = min(dp[i - 1] + 1, i - mp[s[i - 1]]);
            //加入哈希表
            mp[s[i - 1]] = i;
            //维护最大值
            res = max(res, dp[i]);
        }
        return res;
    }
};