LeetCode刷题记录(二十七):无重复字符的最长子串

125 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第27天,点击查看活动详情

无重复字符的最长子串

image.png

题目解析

题目素材解析

根据题目的描述来看,就只给了一个字符串s。

并且这个字符串可能很长,长度最小为0,最大为50000。

并且字符串中可能存在英文、数字、符号、空格等元素。

我的解读

题目的预期结果是要在一个字符串中找出一个最长子串的长度,并且保证这个子串中的字符不重复。

我对本题的思路,其实是有两种方法。

其一,就是暴力美学的做法,利用双重循环来获取结果。但是很不幸,这种方法在我本地执行没有问题,就是慢;但竟然在LeetCode中执行超时,简直欲哭无泪。

其二,也是没有别的办法,为了运行通过,只能尝试其他方法。发现大家都在用滑动窗口的方式。

所以我就理了理思路,大概有以下几个重点需要突破一下。

一,在子串拼接中如何判断是否存在过某字符,可以使用Set集合,不需要字符出现的顺序,只需要判断是否存在某个元素即可。

二,理解滑动窗口的概念,妥善使用索引值。

滑动窗口的图例(从Ikaruga这个大佬题解中拿的)

image.png

解题思路

有了大概的思路,解题也就没那么难了。

特殊情况单独处理一下即可。

第一步,先声明一个结果值result,Set集合(存放字符)。

第二步,声明一个起始位置l。

第三步,根据素材字符串的长度来循环遍历。

第四步,判断是否在Set集合中存在,如果不存在,则证明此窗口往右延伸

第五步,如果存在,则需要窗口头部向尾部缩进,并且要缩进到当前值的下一个位置。

以此类推,得到最终结果。

这道题还是要先理解滑动窗口的概念,才能解出来。

代码

class Solution {
    /**
     * 滑动窗口
     * 弃用split分隔方法,使用charAt方法提升效率。
     * @param s
     * @return
     */
    public int lengthOfLongestSubstring(String s) {
        //处理特殊情况
        if(s.length() == 0){
            return 0;
        }
        //声明一个结果值
        int result = 0;
        //声明一个Set集合
        Set<Character> set = new HashSet<>();
        int l = 0;
        for (int r = 0; r < s.length(); r++) {
            Character si = s.charAt(r);
            if(set.contains(si)){
                int z = l;
                while (true){
                    if(l < r && s.charAt(l++) == s.charAt(r)){
                        break;
                    }else if(l >= r){
                        l = z;
                        break;
                    }
                }
            }
            if(r - l + 1 > result){
                result = r - l + 1;
            }
            set.add(si);
        }
        return result;
    }

}

执行结果

一开始想多判断一下特殊情况,结果聪明反被聪明误,又提交错好几次。

image.png

Java代码本地执行

Java本地可调试代码,请参考github/Ijiran,可通过索引看到相应代码。

如下图所示:

image.png