Leetcode: 3. Longest Substring Without Repeating Characters

Given a string s, find the length of the longest substring without repeating characters.

Example 1:

Input: s = "abcabcbb"
Output: 3
Explanation: The answer is "abc", with the length of 3.

Example 2:

Input: s = "bbbbb"
Output: 1
Explanation: The answer is "b", with the length of 1.

Example 3:

Input: s = "pwwkew"
Output: 3
Explanation: The answer is "wke", with the length of 3.
Notice that the answer must be a substring, "pwke" is a subsequence and not a substring.

Example 4:

Input: s = ""
Output: 0

Constraints:

  • 0 <= s.length <= 5 * 104
  • s consists of English letters, digits, symbols and spaces.

解法一:暴力破解

这个方法就不说了。

解法二:滑动窗口 + HashMap

寻找最长不含重复字符的字符串的过程,就是依次以字符串中的每一位为起始点,判断到该字符之后的每一位字符之间知否包含重复字符的过程。(也就是暴力破解的过程)但是这个过程中最耗时的就是如何快速判断起止字符之间是否包含重复字符。比如有一个10个字符的字符串,当起止点设为从0到5的时候,得知不包含重复字符;那么接下来遍历从0到6的字符串中是否包含重复字符的时候需要重复计算从0到5的情况,这无疑浪费掉了之前的判断结果。再者,假设从0遍历到第5位的时候发现了第5位与第3位字符重复,那么接下来就应该从第4位开始重新向后遍历。那么我们如何才能知道当前遍历的字符和它之前的哪个字符重复呢?理所当然的我们可以用HashMap去记录这个信息,HashMap的key位当前字符,value为该字符所在字符串中的索引值。那么·整个过程就变成:

1)设置i和j两个指针分别做为窗口的起止位,初始值均为0

1)j从字符串中的第0位开始向后遍历,如果hashmap中存在该字符,则说明当前字符与之前的某个字符发生重复。所以需要从hashmap中取出该字符对应的索引,并将该字符对应索引位与i值比较,取最大值做为新的i值(即窗口)

3)每次移动窗口的指针时,同步更新窗口的大小并取最大值即可

    public static int lengthOfLongestSubstring(String s) {
        int n = s.length(), ans = 0;
        Map<Character, Integer> map = new HashMap<>(); // current index of character
        // try to extend the range [i, j]
        for (int j = 0, i = 0; j < n; j++) {
            if (map.containsKey(s.charAt(j))) {
                i = Math.max(map.get(s.charAt(j)), i);
            }
            ans = Math.max(ans, j - i + 1);
            map.put(s.charAt(j), j + 1);
        }
        return ans;
    }

解法三:滑动窗口 + HashSet

刚才的解法中我们是通过一个HashMap去记录字符和索引位的关系,但是其实我们并不是必须去知道具体某个字符在具体哪一位上。假设有字符串abcdecf,当j走到第5位上时,c与第2位字符重复,那么我们期望的是将窗口起始位i调整至第3位。所以我们可以通过类似出栈的操作将指针i移动到指定位置。具体操作:

设置HashSet用来存储已经遍历过的节点。以abcdecf为例,当j从第0位遍历到第4位时,hashset中已经包含了字符abcde,当遍历到下一位第5位时,发现c已经在set中出现过,那么直接将窗口的起始位“i”上的字符移除,并右移 i 一位,“j”位置不变。如果后续继续出现重复的字符,则继续移除i上的字符并右移i。

    public static int lengthOfLongestSubstring(String s) {
        int n = s.length();
        Set<Character> set = new HashSet<>();
        int ans = 0, i = 0, j = 0;
        
        while (i < n && j < n) {
            // try to extend the range [i, j]
            if (!set.contains(s.charAt(j))){
                set.add(s.charAt(j++));
                ans = Math.max(ans, j - i);
            }
            else {
                set.remove(s.charAt(i++));
            }
        }
        return ans;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yexianyi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值