前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >leetcode刷题(3)——无重复字符的最长子串

leetcode刷题(3)——无重复字符的最长子串

作者头像
老马的编程之旅
发布2022-06-22 13:23:36
1860
发布2022-06-22 13:23:36
举报
文章被收录于专栏:深入理解Android

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

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

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

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

解题思路: 这道题主要用到思路是:滑动窗口

什么是滑动窗口?

其实就是一个队列,比如例题中的 abcabcbb,进入这个队列(窗口)为 abc 满足题目要求,当再进入 a,队列变成了 abca,这时候不满足要求。所以,我们要移动这个队列!

如何移动?

我们只要把队列的左边的元素移出就行了,直到满足题目要求!

一直维持这样的队列,找出队列出现最长的长度时候,求出解!

刚开始的想法1: 刚开始想的是判断队列的首和尾是否和即将进来的元素有一致的,如果是首是一致的,就移除首,尾部一致,就将整个队列移除干净,于是有了如下的写法:

代码语言:javascript
复制
class Solution {
    public int lengthOfLongestSubstring(String s) {
        ArrayDeque<Character> arrayDeque = new ArrayDeque<>();
        int maxSize = 0;
        for(int i=0;i<s.length();i++){
            Character charSet = s.charAt(i);
            if(arrayDeque.isEmpty()){
                arrayDeque.add(charSet);
            }else{
                Character firstChar = arrayDeque.peek();
                Character lastChar = arrayDeque.getLast();
                if(firstChar!=null&&firstChar.equals(charSet)){
                    arrayDeque.poll();
                
                }else if(lastChar!=null&&lastChar.equals(charSet)){
                    while(!arrayDeque.isEmpty()){
                        arrayDeque.poll();
                    }
                }
                arrayDeque.add(charSet);
            }
            maxSize = Math.max(maxSize,arrayDeque.size());
        }
        return maxSize;
    }
}

这个直接就错了,如果输入是"abcabcbb",我的写法输出4,正确结果是3,原因是没有考虑中间元素也可能和即将进来的元素会重合。

错误想法2: 决定用left和right来记录滑动窗口的左右边界,于是写了如下写法:

代码语言:javascript
复制
class Solution {
    public int lengthOfLongestSubstring(String s) {
        int left =0;
        int right=0;
        int max = 0;
        HashMap<Character,Integer> map = new  HashMap();
        for(int i=0;i<s.length();i++){
            Character charDex = s.charAt(i);
            if(!map.containsKey(charDex)){
                map.put(charDex,i);
            }else{
                int index = map.get(charDex);
                left = i;
                map.put(charDex,i);
            }
            right = i;
            max = Math.max(right-left+1,max);
        }
        return max;
    }
}

问题就是出在了left的更新上,这里left = i;的话,“dvdf"系统输出3,我输出2,如果是left=index+1;输入"abba”,系统输出2,我输出3, 所以左界限应该定义为 left = Math.max(left,index+1);,这里这个题目唯一难点

通用模版:

代码语言:javascript
复制
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;
        
    }
}

耗时解法1:

代码语言:javascript
复制
public int lengthOfLongestSubstring(String s) {
        char[] chars = s.toCharArray();
        String pre = "";
        int index;
        int max = 0;
        LinkedHashMap<Character, Integer> linkedHashMap = new LinkedHashMap<>();
        ArrayDeque<Character> arrayDeque = new ArrayDeque<>();
        for (index = 0; index < chars.length; index++) {
            char charDex = chars[index];
            if (linkedHashMap.containsKey(charDex)) {
                int indexRepeat = linkedHashMap.get(charDex);
                for (Map.Entry<Character, Integer> entry : linkedHashMap.entrySet()) {
                    int value = entry.getValue();
                    Character key = entry.getKey();
                    if (value <= indexRepeat) {
//                        linkedHashMap.remove(key);
                        arrayDeque.push(key);
                    }
                }
            }
            while (arrayDeque.size() != 0) {
                Character character = arrayDeque.poll();
                linkedHashMap.remove(character);
            }
            linkedHashMap.put(charDex, index);
            max = Math.max(max, linkedHashMap.size());
        }
        return max;

    }

这个是我最初的解法,实在太耗时了,于是优化了一下:

代码语言:javascript
复制
public class Solution {
    public 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;
    }
}

解法3:使用滑动窗口的模版 **注意:**之前滑动窗口的模版可以使用数组来作为 窗口,但是在这个问题上就能不使用了,因为这里没有说字符串只由26个字母组成,所以可能出现“ ”的字符串,必须使用map

代码语言:javascript
复制
class Solution {
    public int lengthOfLongestSubstring(String s) {
        int left =0;
        int right=0;
        int max = 0;
        HashMap<Character,Integer> window = new HashMap();
        
        while(right<s.length()){
            char charDex = s.charAt(right);
            right++;
            window.put(charDex,window.getOrDefault(charDex,0)+1);
            while(window.getOrDefault(charDex,0)>1){
                char leftChar = s.charAt(left);
                window.put(leftChar,window.getOrDefault(leftChar,0)-1);
                left++;
            }
             max = Math.max(right-left,max);
        }
            
        return max;
    }
}

注意:这里的 max = Math.max(right-left,max);是放在while(right<s.length())这个循环中,因为要缩短了左边界,窗口长度固定以后,才开始比较大小

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-07-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档