leetcode-pp / 91alg-5-daily-check

91 天学算法第五期打卡
55 stars 14 forks source link

【Day 22 】2021-10-01 - 3. 无重复字符的最长子串 #37

Open azl397985856 opened 2 years ago

azl397985856 commented 2 years ago

3. 无重复字符的最长子串

入选理由

暂无

题目地址

https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/

前置知识

示例 1:

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

示例 2:

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

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

AnhTom2000 commented 2 years ago

思路

滑动窗口,每次尝试扩大窗口,当没有出现重复字符时,right指针向右不断扩大窗口长度,有重复的字符,就让left指针右移,不断缩短窗口长度,每次都维护这个窗口的最大长度

代码:Java

class Solution {
     public int lengthOfLongestSubstring(String s) {
        // 哈希集合,记录每个字符是否出现过
        Map<Character,Integer> occ = new HashMap<>();
        int left = 0;
        int right = 0;
        int res = 0;

      while(right < s.length()){
        char c =  s.charAt(right);
        right++;
        occ.put(c,occ.getOrDefault(c,0)+1);
        while(occ.get(c) > 1){
          char cc = s.charAt(left);
          occ.put(cc , occ.get(cc) - 1);
          left++;
        }
        res = Math.max(res,right - left);
      }
      return res;
    }
} 

复杂度分析

时间复杂度:O(n)

空间复杂度:O(n)

标签

哈希表,字符串,滑动窗口

simonsayshi commented 2 years ago

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        if(s.size()==0)
            return 0;
        unordered_map<char, int> m;
        int maxLen = INT_MIN, left = -1;

        for(int i = 0;i < s.size();i++) {

            if(m.find(s[i]) != m.end()&& m[s[i]] > left) { //保证当前边界的前一个值
                left = m[s[i]];
            }       
           m[s[i]] = i;
            maxLen = max(maxLen, i - left);
        }
        return maxLen;
    }
};
ff1234-debug commented 2 years ago

思路:

方法: map + 滑动窗口

RonghuanYou commented 2 years ago
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        visitedcharIndex = {}
        start, maxLength = 0, 0

        for i in range(len(s)):
            endChar = s[i]
#           we hit the new char has been visited, it need to delete the exisiting one, contract the window
            if endChar in visitedcharIndex:
#               if newChar's index in dict is greater than start index  (abba)
                if visitedcharIndex[endChar] >= start:
                    start = visitedcharIndex[endChar] + 1
            visitedcharIndex[s[i]] = i
            maxLength = max(maxLength, i - start + 1)
        return maxLength
QiZhongdd commented 2 years ago

var lengthOfLongestSubstring = function(s) { let l=0,r=0,ans=0; const map = {}; while(r<s.length){ let pos=map[s[r]]; if(l<=pos&&pos<=r){ l=pos+1 } map[s[r]]=r; ans=Math.max(ans,r-l+1); r++; } return ans

};

HarleysZhang commented 2 years ago

解题思路

  1. 动态规划。参考这里
  2. 滑动窗口法 + 哈希表结构。

C++代码

class Solution {
public:
    // 动态规划+线性遍历
    int lengthOfLongestSubstring(string s) {
        int res=0, tmp = 0, i=0;
        for(int j=0; j < s.size(); j++){
            i = j-1;
            while(i>=0 && s[i] != s[j]) i-= 1;
            if(tmp < j-i) tmp += 1;
            else tmp = j - i;
            res = max(res, tmp);
        }
        return res;
    }
    // 滑动窗口法 +  哈希表保存字符出现的位置
    int lengthOfLongestSubstring2(string s) {
        unordered_map<char, int> seen;
        int maxLength = 0, l = 0;
        for(int r=0; r<s.size(); r++){
            // 更新滑动窗口左侧位置
            if(seen.count(s[r]) > 0) {
                int last_pos = seen[s[r]];
                // 位置判断不可少,重复字符的位置必须是在滑动窗口内!
                if(last_pos >= l && last_pos <= r) l = last_pos + 1;
            }
            maxLength = max(maxLength, r-l+1);
            seen[s[r]] = r;
        }
        return maxLength;
    }
};
xingkong1994 commented 2 years ago

思路

从首字符开始遍历,遍历的时候用map进行存储记录。

代码

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int max_length = 0;
        if (s.empty())  return 0;
        map<char, int> mymap;
        for (int i = 0; i < s.length(); i++) {
            for (int j = i; j < s.length(); j++) {
                if (mymap[s[j]] > 0) {
                    break;
                }
                mymap[s[j]]++;
            }
            max_length = max_length > mymap.size()? max_length : mymap.size();
            mymap.clear();
        }
        return max_length;
    }
};

复杂度

时间: O(n^2) 空间: O(n)

raoshuang commented 2 years ago

//针对不重复字符的判断和处理,可以用hash //方法一:用hashset class Solution { public: int lengthOfLongestSubstring(string s) { unordered_set str; int fast = 0; int slow = 0; int len = 0; if(s.size()==0){ return 0; } for(;fast<s.size();fast++){ while(str.count(s[fast])==1){ str.erase(s[slow]); slow++; } str.insert(s[fast]); len = max(len,fast-slow+1); } return len; } };

wangwiitao commented 2 years ago

思路

双指针,一个向前如果hash table中没有就存进去,并计算最大值,如果有,删除另一个指针(该指针向前),直到不重复。

代码

var lengthOfLongestSubstring = function (s) {
    let set = new Set();
    let i = 0, j = 0, res = 0;
    if(s.length ===0 ) return 0;
    for(i;i<s.length;i++){
        if(!set.has(s[i])){
            set.add(s[i]);
            res = Math.max(res,set.size);
        }else{
            while(set.has(s[i])){
                set.delete(s[j]);
                j++
            }
            set.add(s[i]);
        }
    }
    return res;
};
iambigchen commented 2 years ago

思路

滑动窗口求最长不重复字符串长度,当遇到重复的字符在窗口内中,窗口的左侧移动到重复字符串后一位,右侧加一。

代码

var lengthOfLongestSubstring = function(s) {
    let l = 0
    let r = 0
    let max = 0
    let map = {}
    while(r < s.length) {
        let cur = s[r]
        if (map[cur] <= r && map[cur] >= l) {
            l = map[cur] + 1
        }
        map[cur] = r
        max = Math.max(max, r - l + 1)
        r++
    }
    return max
};

复杂度

时间复杂度 O(N) 空间复杂度 O(N)

chanceyliu commented 2 years ago

思路

官方题解,先 Mark 后看

代码

var lengthOfLongestSubstring = function (s) {
  // 哈希集合,记录每个字符是否出现过
  const occ = new Set();
  const n = s.length;
  // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
  let rk = -1,
    ans = 0;
  for (let i = 0; i < n; ++i) {
    if (i != 0) {
      // 左指针向右移动一格,移除一个字符
      occ.delete(s.charAt(i - 1));
    }
    while (rk + 1 < n && !occ.has(s.charAt(rk + 1))) {
      // 不断地移动右指针
      occ.add(s.charAt(rk + 1));
      ++rk;
    }
    // 第 i 到 rk 个字符是一个极长的无重复字符子串
    ans = Math.max(ans, rk - i + 1);
  }
  return ans;
};

复杂度分析

chaggle commented 2 years ago

title: "Day 22" date: 2021-10-01T16:26:21+08:00 draft: true

3. 无重复字符的最长子串

题目

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

 

示例 1:

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

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

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

输入: s = ""
输出: 0
 

提示:

0 <= s.length <= 5 * 104
s 由英文字母、数字、符号和空格组成

题目思路

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int n = s.size();
        unordered_set<char> ans;
        int str = 0;
        int l = 0;
        for(int i = 0; i < n; i++)
        {
            while(ans.find(s[i]) != ans.end()) 
            {
                ans.erase(s[l]);
                l++;
            }
            str = max(str, i - l + 1);
            ans.insert(s[i]);
        }
        return str;
    }
};

复杂度

EggEggLiu commented 2 years ago

思路

双指针。将遍历过的字符存到hashMap中,一旦再次遍历到,就移动前面的指针直至不重复。

代码

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        map<char, int> mp;
        int first = 0;
        int second = 0;
        const size_t size = s.size();
        int res = 0;
        while (second < size) {
            if (!mp[s[second]]) {
                res = max(res, second - first + 1);
            } else {
                while (mp[s[second]]) {
                    mp.erase(s[first++]);
                }
            }
            mp[s[second++]] = 1;
        }
        return res;
    }
};

复杂度

时间O(n)

空间O(1)

LareinaWei commented 2 years ago

Thinking

Use a hashmap to store the index of the current character in the string, check each time if the current character is in the hashmap, if is, update the start index of the substring, if not, check if the current sub-string is longer than the current max and update the max accordingly.

Code

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        dic = {}
        start = 0
        res = 0
        for i in range(len(s)):
            if s[i] in dic and start <= dic[s[i]]:
                start = dic[s[i]] + 1
            else:
                res = max(i - start + 1, res)
            dic[s[i]] = i

        return res

Complexity

Time complexity: O(n) Space complexity: O(n)

okbug commented 2 years ago

思路

哈希表,如果遇到了重复的字符串,那么就记录最大的 start 开始的时间,也是滑动窗口

代码

语言: C++

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char, int> map;
        int res = 0, start = 0;
        for (int i = 0; i < s.size(); i++) {
            char c = s[i];
            if (map.count(c)) {
                start = max(start , map[c] + 1);
            }

            res = max(res, i - start + 1);
            map[c] = i;
        }

        return res;
    }
};
taojin1992 commented 2 years ago

Plan:

map + two pointers
char - index map

if see duplicate, if previous dup index is between current start and end, start reset start = prevDupPos + 1

Time: O(n), n = s.length()

Space: number of unique chars, O(s), given the constraints (English letters, digits, symbols and spaces.)

Tests:

"abc"
"aaa"
a-0
"abcab"
a-0
b-1
c-2

longest = 3-0 = 3
start = 1
a-3
b-1
c-2

"pwwkew"
3
"abcabc"
a-0
b-1
c-2

"abba"

a 0
b 1

Code:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character, Integer> charIndexMap = new HashMap<>();
        int longest = 0, start = 0, end = 0; // inclusive
        int prevDupPos = -1;
        for (end = 0; end < s.length(); end++) {
            char cur = s.charAt(end);

            if (charIndexMap.containsKey(cur)) {
                prevDupPos = charIndexMap.get(cur);
                // think about case "abba"
                if (prevDupPos >= start && prevDupPos <= end) {
                    start = prevDupPos + 1;
                }

            } 
            charIndexMap.put(cur, end);
            // System.out.println("start:" + start + ",end=" + end);
            longest = Math.max(longest, end - start + 1);
        }
        return longest;
    }
}
potatoMa commented 2 years ago

思路


双指针+Set

代码


JavaScript Code

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
    if(!s) return 0;
    if (s.length === 1) return 1;
    const set = new Set();
    let i = 0, j = 0, res = 0;
    while (i < s.length) {
        const char = s[i];
        while (set.has(char)) {
            set.delete(s[j]);
            j++
        }
        set.add(char);
        i++;
        res = Math.max(res, i - j);
    }
    return res;
};

复杂度分析


时间复杂度:O(N)

空间复杂度:O(N),N为字符集大小

suukii commented 2 years ago

3. 无重复字符的最长子串

https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/

题目描述

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

示例 1:

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

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

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

方法 1:滑动窗口+哈希表

思路

复杂度分析

代码(JavaScript/C++)

JavaScript Code

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function (s) {
    const map = {};
    let l = 0,
        r = 0,
        max = 0;

    while (r < s.length) {
        const pos = map[s[r]];
        // 如果 s[r] 曾在 [l, r] 滑动窗口中出现
        // 就收缩滑动窗口左侧,把 l 指针移动到 s[r] 上次出现的位置 + 1
        if (pos >= l && pos <= r) l = pos + 1;

        // 更新 s[r] 出现的位置
        map[s[r]] = r;
        // 计算滑动窗口大小
        max = Math.max(max, r - l + 1);
        // 滑动窗口继续右移扩张
        r++;
    }
    return max;
};

C++ Code

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char,int> seen;
        int max_len = 0, l = 0, r = 0;
        while (r < s.size()) {
            if (seen.count(s[r]) > 0) {
                int last_pos = seen[s[r]];
                if (last_pos >= l && last_pos <= r) {
                    l = last_pos + 1;
                }
            }
            max_len = max(max_len, r - l + 1);
            seen[s[r]] = r;
            r++;
        }
        return max_len;
    }
};

更多题解可以访问:https://github.com/suukii/91-days-algorithm

newbeenoob commented 2 years ago

思路


维护一个可变的滑动窗口,以及一个哈希表,窗口的右边界负责在符合条件(窗口内无重复元素) 的情况下向前滑动,窗口的左边界负责在窗口不符合条件的时候收缩窗口,直到窗口再次符合条件,每次在右边界向前滑动的时候记录当前的窗口长度,更新答案,就可以找到符合条件的最长子串。

代码:JavaScript


var lengthOfLongestSubstring = function(s) {

    if(!s.length) return 0;

    s = s.split('');

    let l = 0 , r = 1;

    const hash = Object.create(null);

    hash.add = function (key) {
        this[key] !== void 0 ? this[key]++ : this[key] = 1;
    }

    hash.del = function (key) {
        this[key]--;
    }

    hash.has = function (key) {
        return !!this[key];
    }

    const window = Object.create(hash);

    window.add(s[l]);

    let ans = 1;

    while(r <= s.length) {
        // 尝试扩窗
        while(r < s.length && !window.has(s[r])) {
            ans = Math.max(ans , r - l + 1); // 更新答案
            window.add(s[r]); // 往窗口内增加元素
            ++r;
        }

        if (r >= s.length) break;

        // 缩窗
        while(l < r && window.has(s[r])) {
            window.del(s[l]); // 从窗口内移除元素
            ++l;
        }

    }

复杂度分析


使用内置排序:

标签


哈希表双指针 , 滑动窗口

Lydia61 commented 2 years ago

无重复字符串的最大长度

思路

代码

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        occ = set()
        n = len(s)
        rk, ans = -1, 0
        for i in range(n):
            if i != 0:
                occ.remove(s[i - 1])
            while rk + 1 < n and s[rk + 1] not in occ:
                occ.add(s[rk + 1])
                rk += 1
            ans = max(ans, rk - i + 1)
        return ans

复杂度分析

kbfx1234 commented 2 years ago

3. 无重复字符的最长子串

// 10-01
class Solution {
public:
// 滑动窗口
    int lengthOfLongestSubstring(string s) {
        if (s.size() == 0) return 0;
        unordered_set<char> uset;
        int length = 0;
        int left = 0;
        for (int i = 0; i < s.size(); i++) {
            while (uset.find(s[i]) != uset.end()) {
                uset.erase(s[left]);
                left++;
            }
            uset.insert(s[i]);
            length = max(length, i - left + 1);
        }
        return length;
    }
};
xiezhengyun commented 2 years ago

思路

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function (s) {
  var map = new Map()
  var count = 0, j = 0;
  for (let i = 0; i < s.length; i++) {
    if (!map.has(s[i])) {
      map.set(s[i], s[i])
      count = map.size > count ? map.size : count
    } else {
      while(map.has(s[i])){
        map.delete(s[j])
        j++
      }
      map.set(s[i], s[i])
    }
  }
  return count
};

复杂度

asterqian commented 2 years ago

思路

滑动窗口思想,一边扫描一边检查当前char是不是已经出现过,如果出现过,则把左边指针移动到上次出现的位置的后一位

代码

int lengthOfLongestSubstring(string s) {
    unordered_map<char, int> seen;
    int ans = 0, l = 0, r = 0;
    while (r < s.size()) {
        if (seen.find(s[r]) != seen.end()) {
            int prev = seen[s[r]];
            if (prev >= l && prev <= r) {
                l = prev + 1;
            }
        }
        ans = max(ans, r - l + 1);
        seen[s[r]] = r;
        r++;
    }
    return ans;
}

复杂度分析

时间复杂度: O(N)
空间复杂度: O(s)
nekomoon404 commented 2 years ago

【思路—哈希表+滑动窗口】

int lengthOfLongestSubstring(string s) {
        int n = s.size();
        unordered_map<char, int> map;
        int ans = 0, l = 0, r = 0;

        while(r < n) {
            if(map.find(s[r]) != map.end()) {
                int last_pos = map[s[r]];
                if(last_pos >= l) {    //当重复元素上次出现的位置大于等于窗口左边界时,才更新左边界
                    l = last_pos + 1;
                }
            }
            ans = max(ans, r - l + 1);
            map[s[r]] = r;
            r++;
        }

        return ans;
    }

时间复杂度:$O(n)$;空间复杂度:$O(n)$

Bingbinxu commented 2 years ago

思路 官方思路:判断树s[r]是否存在,存在的话: 1.如果重复,左侧向右移动一位 2.如果不重复,扩展右侧 记录最长的长度 代码

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char ,int> spl;
        int max_len = 0, l = 0, r = 0;
        while(r<s.size())
        {
            if(spl.count(s[r])>0) //判断树s[r]是否存在
            {
                int last = spl[s[r]];
                if (last >= l && last <= r)
                l = last +1; //如果重复,左侧向右移动一位
            }
            max_len = max(max_len, r -l +1); //记录最长的长度
            spl[s[r]] = r;
            r ++;
        }
        return max_len;
    }
};

复杂度 时间复杂度:排序算法O(N) 空间复杂度:存储所有的节点O(S)S为不重复字符串长度

yibenxiao commented 2 years ago

【Day 22】3. 无重复字符的最长子串

思路

想象有个滑块在字符串上滑动

代码

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        used = {}
        max_length = start = 0
        for i, c in enumerate(s):
            if c in used and start <= used[c]:
                start = used[c] + 1
            else:
                max_length = max(max_length, i - start + 1)

            used[c] = i

        return max_length

复杂度

时间复杂度:O(N) 空间复杂度:O(N)

HondryTravis commented 2 years ago

思路

使用滑动窗口的方法,

  1. 使用map记录每个字符出现最近一次出现的下标
  2. 当遇到重复字符时,下次便从相应下标 i + 1 的地方开始读取

代码

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
    const map = {}
    let l = 0, r = 0, m = 0
    while (r < s.length) {
        const c = s[r]
        // 如果map存在存在上次的位置,就直接用,否则就0
        l = Math.max(l, map[c] ?? 0)
        // => r - l + 1 = 长度
        m = Math.max(m, r - l + 1)
        r ++
        map[c] = r
    }
    return m
};

复杂度

时间复杂度: O(n)

空间复杂度: O(n)

naomiwufzz commented 2 years ago

思路:hashmap + 双指针

用双指针确定最长字串的左右位置。用hash记录最近见到的某个字符。如果发现出现了重复字符,那么在hash中找到这个字符最近出现的地方,把左指针移动过来

代码

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        max_len = 0
        hash_map = dict()
        left, right = 0, 0
        if len(s) <= 1:
            return len(s)
        hash_map[s[left]] = 0
        while right < len(s):
            if s[right] in s[left:right]: # 说明有重复了
                max_len = max(max_len, right-left)
                left = hash_map[s[right]] + 1
            else:
                max_len = max(max_len, right-left)
            hash_map[s[right]] = right
            right += 1
        max_len = max(max_len, right-left)
        return max_len

复杂度分析

guangsizhongbin commented 2 years ago

class Solution { public int lengthOfLongestSubstring(String s) { // 记录字符上一次出现的位置 int[] last = new int[128]; for(int i = 0; i < 128; i++) { last[i] = -1; } int n = s.length();

    int res = 0;
    int start = 0; // 窗口开始位置
    for(int i = 0; i < n; i++) {
        int index = s.charAt(i);
        start = Math.max(start, last[index] + 1);
        res   = Math.max(res, i - start + 1);
        last[index] = i;
    }

    return res;
}

}

shawncvv commented 2 years ago

思路

官方解题思路

代码

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function (s) {
    const map = {};
    let l = 0,
        r = 0,
        max = 0;

    while (r < s.length) {
        const pos = map[s[r]];
        // 如果 s[r] 曾在 [l, r] 滑动窗口中出现
        // 就收缩滑动窗口左侧,把 l 指针移动到 s[r] 上次出现的位置 + 1
        if (pos >= l && pos <= r) l = pos + 1;

        // 更新 s[r] 出现的位置
        map[s[r]] = r;
        // 计算滑动窗口大小
        max = Math.max(max, r - l + 1);
        // 滑动窗口继续右移扩张
        r++;
    }
    return max;
};

复杂度

Shinnost commented 2 years ago

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        occ = set()
        n = len(s)
        rk, ans = -1, 0
        for i in range(n):
            if i != 0:
                occ.remove(s[i - 1])
            while rk + 1 < n and s[rk + 1] not in occ:
                occ.add(s[rk + 1])
                rk += 1
            ans = max(ans, rk - i + 1)
        return ans
HWFrankFung commented 2 years ago

Ideas

Codes


var lengthOfLongestSubstring = function (s) {
    let l = 0; 
    let res = 0; 
    let map = new Map(); 
    for (let r = 0; r < s.length; r++) {
        if (map.has(s[r]) && map.get(s[r]) >= l) {
            l = map.get(s[r]) + 1;
        }
        res = Math.max(res, r - l + 1); 
        map.set(s[r], r); 
    }
    return res;
};
Richard-LYF commented 2 years ago

class Solution: def lengthOfLongestSubstring(self, s: str) -> int: k, res, c_dict = -1, 0, {} for i, c in enumerate(s): if c in c_dict and c_dict[c] > k: # 字符c在字典中 且 上次出现的下标大于当前长度的起始下标 k = c_dict[c] c_dict[c] = i else: c_dict[c] = i res = max(res, i-k) return res

mannnn6 commented 2 years ago

思路

滑动窗口

代码

class Solution {
    public int lengthOfLongestSubstring(String s) {
        Set<Character> occ = new HashSet<Character>();
        int n = s.length();
        int rk = -1, ans = 0;
        for (int i = 0; i < n; ++i) {
            if (i != 0) {
                occ.remove(s.charAt(i - 1));
            }
            while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) {
                occ.add(s.charAt(rk + 1));
                ++rk;
            }
            ans = Math.max(ans, rk - i + 1);
        }
        return ans;
    }
}

复杂度

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

kendj-staff commented 2 years ago
class Solution {
    public int lengthOfLongestSubstring(String s) {
        Set<Character> set = new HashSet<Character>();
        int maxLen = 0;
        int j = 0;
        for (int i = 0; i < s.length(); i++) {

            if (i > 0) {
                set.remove(s.charAt(i - 1));
            }
            while (j < s.length() && !set.contains(s.charAt(j))) {
                set.add(s.charAt(j));
                j++;
            }
            maxLen = (maxLen > j - i ? maxLen : j - i);
        }
        return maxLen;
    }
}
for123s commented 2 years ago

C++ Code:


class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        if(s.size()==0)
            return 0;
        unordered_map<char,int> mp;
        int l = 0, r = 1;
        int ret = 1;
        mp[s[0]] = 0;
        while(r<s.size())
        {
            if(mp.count(s[r])==0||mp[s[r]]==-1)
            {
                mp[s[r]] = r;
                ret = max(ret, r+1-l);
            }
            else
            {
                while(s[l]!=s[r])
                    mp[s[l++]] = -1;
                l++;
                mp[s[r]] = r;
            }
            ++r;
        }
        return ret;
    }
};

复杂度分析

令 n 为数组长度。

learning-go123 commented 2 years ago

思路

代码

Go Code:


func lengthOfLongestSubstring(s string) int {
    var win [96]int
    var res, left int
    for i:=0;i<len(s);i++ {
        c := s[i] - 31
        win[c]++

        for win[c] > 1 {
            win[s[left]- 31]--
            left++
        }

        if res < i-left+1 {
            res = i-left+1
        }
    }
    return res
}

复杂度分析

令 n 为数组长度。

FullStackH commented 2 years ago

class Solution { public int lengthOfLongestSubstring(String s) { if (s.length()==0) return 0; HashMap<Character, Integer> map = new HashMap<Character, Integer>(); int max = 0; int left = 0; for(int i = 0; i < s.length(); i ++){ if(map.containsKey(s.charAt(i))){ left = Math.max(left,map.get(s.charAt(i)) + 1); } map.put(s.charAt(i),i); max = Math.max(max,i-left+1); } return max;

}

}

DoubleW2w commented 2 years ago

思路:哈希表+双指针 👌🏻

维护一个滑动窗口,窗口内就是无重复字符的最长子串。让我们遇到了重复字符时,把窗口左边字符排除,直到满足题目要求

代码🔤

Java Code:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if (s.length()==0) return 0;

        HashMap<Character, Integer> map = new HashMap<Character, Integer>();
        //不重复子串的开始位置为 start,结束位置为 end
        int max = 0;
        int start = 0;
        for(int end = 0; end < s.length(); end++){
            if(map.containsKey(s.charAt(end))){
                //移动left指针到重复字符后一个
                //保证[start, end] 无重复字符
                start = Math.max(start, map.get(s.charAt(end)) + 1);
            }
            map.put(s.charAt(end), end);
            max = Math.max(max, end - start + 1);
        }
        return max;
    }
}

复杂度分析

令 n 为字符串长度。

shixinlovey1314 commented 2 years ago

Title:3. Longest Substring Without Repeating Characters

Question Reference LeetCode

Solution

Use slide window and hashmap. Slide window to store the substring that has no repeat characters, hashmap used to count the number of times each character appears.

Code

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int len = 0;
        unordered_map<char, int> counter;

        for (int l = 0, r = 0; r < s.length(); r++) {
            counter[s[r]]++;

            while ((r - l + 1) > counter.size()) {
                counter[s[l]]--;
                if (counter[s[l]] == 0) {
                    counter.erase(s[l]);
                }

                l++;
            }

            len = max(len, r - l + 1); 
        }

        return len;
    }
};

Complexity

Time Complexity and Explanation

O(n), we visit each number at most twice

Space Complexity and Explanation

O(n), for the hashmap

ysy0707 commented 2 years ago

思路:哈希表

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int len = s.length();
        int max = 0;

        Map<Character,Integer> map = new HashMap<>();
        for(int start = 0, end = 0; end < len; end++){
            char c = s.charAt(end);
            if(map.containsKey(c)){
                //提前在map.get()处进行+1操作
                start = Math.max(map.get(c) + 1, start);
            }
            max = Math.max(max,end - start + 1);
            //重新更新一下c第一次出现的位置
            map.put(c,end);
        }
        return max;
    }
}

时间复杂度:O(N) 空间复杂度:O(N)

ymkymk commented 2 years ago

思路

一般解法

代码

``

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if (s == null || "".equals(s)) {
            return 0;
        }

        if ("".equals(s.trim())) {
            return 1;
        }

        int max = 1;
        char s0 = s.charAt(0);
        StringBuffer validStr = new StringBuffer(s0+"");
        for (int i = 1; i < s.length(); i++) {
            //说明不存在
            if (validStr.toString().indexOf(s.charAt(i)) == -1) {
                validStr.append(s.charAt(i));
            } else {
                //如果存在重复
                max = Math.max(max, validStr.toString().length());
                int start = validStr.toString().indexOf(s.charAt(i));
                validStr = new StringBuffer(validStr.toString().substring(start + 1));
                validStr.append(s.charAt(i));
            }
        }

        max = Math.max(max, validStr.toString().length());
        return max;
    }
}

复杂度分析

时间复杂度:O(n)

空间复杂度:O(n)

watchpoints commented 2 years ago

class Solution {
public:
    int lengthOfLongestSubstring(string s) {

        int ret =0;
        int begin =0; //开始位置
        int end =0;

        vector<int> hash(128,-1); //hash[s[i]]=i;
         //tieme :o(n)  
        for(end =0;end<s.size();end++)
        {
            char temp =s[end];

            if(hash[temp]!=-1 && hash[temp] >=begin)
            {
                begin=hash[temp]+1;//o(1)
            }

            ret =max(ret,end-begin+1); //长度计算。

            hash[temp]=end;
        }

        return ret;
    }
};
~~~
AruSeito commented 2 years ago
var lengthOfLongestSubstring = function(s) {
    let res = [],max=0

    for(let i = 0 ; i < s.length ; i++){
        let index = res.indexOf(s[i]);
        if(index !== -1){
            res.splice(0,index + 1);
        }
        res.push(s[i]);
        max = Math.max(res.length,max);
    }
    return max;
};
Cartie-ZhouMo commented 2 years ago

思路

滑窗+哈希表,维护窗口内无重复字符,那么最大窗口长度就是无重复字符最长子串。窗口内字符用哈希表保存,遇到重复字符时,弹出窗口左端字符。

代码

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        hashset = set()
        l = r = 0
        ans = 0
        while r < len(s):
            if s[r] in hashset:
                hashset.remove(s[l])
                l += 1
            else:
                hashset.add(s[r])
                r += 1
            ans = max(ans, len(hashset))
        return ans

复杂度

q815101630 commented 2 years ago

Thought

使用双指针,左边指针代表当前正在考虑的substr 末尾,右指针代表当前正在考虑的substr 开头。因为我们的目的是找到最长不重复的substr,我们可以把所有substr所有char存在一个set里,一旦当前右指针在到达下一个 index时发现当前char在set里,说明我们碰到了重复的,需要通过左指针一直做remove,因为substr必须保持连续,所有需要使用while 一直remove左指针上的值

class Solution(object):
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """
        left = 0
        curZone = set()
        maxLength = 0

        for right in range(len(s)):
            while s[right]in curZone:
                curZone.remove(s[left])
                left+=1

            curZone.add(s[right])
            maxLength = max(maxLength,right-left+1)

        return maxLength

Time: 遍历了一次str, O(n)

Space: 需要一个Set, O(n)

joeytor commented 2 years ago

思路

滑动窗口, 右指针一直向右直到有一个字符出现了两次, 此时左指针一直向右直到那个字符又只出现一次

每次都对比 max_len 和 right - left 并更新最大的长度

代码

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:

        left, right = 0, 0

        count_dict = {}

        max_len = 0

        repeat = False

        while right < len(s):

            c = s[right]

            count_dict[c] = count_dict.get(c, 0) + 1

            right += 1

            while count_dict[c] > 1:
                c1 = s[left]

                if c1 in count_dict:
                    count_dict[c1] -= 1

                left += 1

            max_len = max(max_len, right - left)

        return max_len

复杂度

时间复杂度: O(N) 两个指针都是最多遍历一次 string s

空间复杂度: O(N) 哈希表的最差复杂度是 O(N))

BreezePython commented 2 years ago

思路

哈希表+ 滑动窗口

代码

class Solution:
    def lengthOfLongestSubstring(self, s):
        calc = {}
        left = 0
        ret = 0
        for i, j in enumerate(s):
            if j in calc:
                # 如果重复的数字出现在l之前忽略,否则了跳到该值的下一个位置
                left = max(left, calc[j] + 1)
            calc[j] = i
            ret = max(ret, i - left + 1)
        return ret

复杂度

zszs97 commented 2 years ago

开始刷题

题目简介

【Day 22】2021-10-1 - (3. 无重复字符的最长子串)

题目思路

题目代码

代码块

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        // 哈希集合,记录每个字符是否出现过
        unordered_set<char> occ;
        int n = s.size();
        // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
        int rk = -1, ans = 0;
        // 枚举左指针的位置,初始值隐性地表示为 -1
        for (int i = 0; i < n; ++i) {
            if (i != 0) {
                // 左指针向右移动一格,移除一个字符
                occ.erase(s[i - 1]);
            }
            while (rk + 1 < n && !occ.count(s[rk + 1])) {
                // 不断地移动右指针
                occ.insert(s[rk + 1]);
                ++rk;
            }
            // 第 i 到 rk 个字符是一个极长的无重复字符子串
            ans = max(ans, rk - i + 1);
        }
        return ans;
    }
};

复杂度

jinmenghan commented 2 years ago

题目地址()

https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/

题目描述

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

示例 1:

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

示例 2:

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

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

前置知识

思路

标签:滑动窗口 暴力解法时间复杂度较高,会达到 O(n^2)O(n 2 ),故而采取滑动窗口的方法降低时间复杂度 定义一个 map 数据结构存储 (k, v),其中 key 值为字符,value 值为字符位置 +1,加 1 表示从字符位置后一个才开始不重复 我们定义不重复子串的开始位置为 start,结束位置为 end 随着 end 不断遍历向后,会遇到与 [start, end] 区间内字符相同的情况,此时将字符作为 key 值,获取其 value 值,并更新 start,此时 [start, end] 区间内不存在重复字符 无论是否更新 start,都会更新其 map 数据结构和结果 ans。 时间复杂度:O(n)O(n)

代码

Java Code:


class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length(), ans = 0;
        Map<Character, Integer> map = new HashMap<>();
        for (int end = 0, start = 0; end < n; end++) {
            char alpha = s.charAt(end);
            if (map.containsKey(alpha)) {
                start = Math.max(map.get(alpha), start);
            }
            ans = Math.max(ans, end - start + 1);
            map.put(s.charAt(end), end + 1);
        }
        return ans;
    }
}

复杂度分析

令 n 为数组长度。