LeetCode/3. Longest Substring Without Repeating Characters.md

2.4 KiB
Raw Blame History

3. Longest Substring Without Repeating Characters

思路

思路一、暴力动归

用一个与s等长数组dp记录以某个字符结尾的最长不重复子串的长度dp[i]=m表示以s[i]结尾的最长不重复子串的长度为m。所以dp初始化全为1.
dp[i]应该这样计算:

  • 从s[i-1]开始往前遍历dp[i-1]个字符若中途遍历到某个字符与s[i]相等了则跳出循环。若往前遍历了tmp(从0开始)个字符,则dp[i] += tmp

时间复杂度O(n*n)空间复杂度O(n)

思路二、窗口法

用一个hash map(这里直接用一个长为128数组就行了因为ASCII就是0-127)mp记录某个字符c在s中的位置初始全-1.
用left、i记录当前窗口左、右边的位置窗口[left ~ i]中保证是无重复的。
left和i初始都为0i从0开始不断加1并按下面步骤循环:

  1. 设当前字符为cmp[c] >= left则字符c第二次出现在了窗口中left即将右移先更新res再将left移动到上一个c的下一个位置;否则什么都不做。
  2. 最后更新mp: mp[c] = i

时间复杂度O(n)空间复杂度O(1)

C++

思路一

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        if(s.size() == 0) return 0;
        vector<int>dp(s.size(), 1); 
        int res = 1;
        for(int i = 1; i < s.size(); i++){
            int tmp = 0;
            for(; tmp < dp[i - 1]; tmp++){  // 往前遍历dp[i - 1]个字符
                if(s[i] == s[i - 1 - tmp]) break;
            }
            dp[i] = dp[i] + tmp;
            res = (dp[i] > res ? dp[i]:res);
        }
        return res;
    }
};

思路二

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        vector<int>mp(128, -1); // 记录s中某个字符所在位置初始为-1 (数组大小设置成256貌似快一些不知道为啥)
        int left = 0, res = 0, i = 0; // 窗口[left ~ i]中保证是无重复的
        for(; i < s.size(); i++){
            char c = s[i];
            if(mp[c] >= left) { // 字符c第二次出现在了窗口中left即将右移先更新res
                res = max(res, i - left);
                left = mp[c] + 1; // left右移到上一个c所在位置的下一个位置
            }
            mp[c] = i; // 当前字符c的位置
        }
        return max(res, i - left);
    }
};