【LeetCode笔记】3. 无重复字符的最长子串(JAVA、滑动窗口、字符串)

题目描述

  • 子串:各字符间必须要相邻,而非子序列
  • 使用滑动窗口来做就行
    在这里插入图片描述

思路 && 代码

1. 之前的版本

  • 思路:维护一个滑动窗口,滑动窗口中容纳一个无重复字符的子串。
  • 滑动窗口左边界移动的情况:
    1. 【abc】 a => a【bca】
    2. 【abcd】 c => abc【dc】
  • 其实以上两种情况殊途同归,都是把左边界换成当前判断字符在HashMap中对应的下标的位置的后一个
    然后把前面的字符全都丢弃即可(在HashMap中remove())。
  • 左边界移动的情况,需要进行长度的判断:当前滑动窗口长度可能会改变,如果比当前存储的最大长度要大,那么就需要更新。
  • 为什么可以这样子:特别记录一下,这道题其实老早就通过了。。但是之后考虑情况多了,出现了觉得自己写的代码其实考虑不周,但是就是过了的情况= =。
    主要是有这个注意点:在上面的左边界移动情况2,考虑到abc都被丢弃,但是有没有可能a、b实际上可能可以创造最长子串呢? 答案是没有,因为实际上最多的长度【abcd】已经被记录下来了,b最多就是【bcd】c的情况,a也同理,因此已经可以直接丢弃掉了。
class Solution {
    public int lengthOfLongestSubstring(String s) {
        int len=0, lenNow=0;
        HashMap<Character,Integer> hashMap = new HashMap<>();
        for(int i=0;i<s.length();i++){
            if(hashMap.containsKey(s.charAt(i))){
                // 和left.char相同的情况下,可以继续
                // 这个if是个优化,但是其实删掉也可以,之后的代码对于这种情况达到一样的效果
                if(hashMap.get(s.charAt(i))==i-lenNow){
                    hashMap.put(s.charAt(i),i);
                    continue;
                }
                // 否则需要把前面的全删了
                len = Math.max(len,lenNow);
                // 获取当前重复值的下标。
                int temp = hashMap.get(s.charAt(i));
                // 维护哈希表:把不需要的映射remove掉。
                for(int j = i-lenNow;j<=temp;j++){
                    hashMap.remove(s.charAt(j),j);
                }
                // 更新当前滑动窗口的长度
                lenNow = i - temp;
                hashMap.put(s.charAt(i),i);
            }
            else{
                hashMap.put(s.charAt(i),i);
                lenNow++;
            }
        }
        // 一直数到字符串结束的情况,补一个补充
        return Math.max(len,lenNow);
    }
}
  • 时间复杂度:O(N),实际上整个流程本质上就是对字符串的每一个元素都必然访问一次可能删除一次
  • 空间复杂度:O(字符集的大小),因为我们需要简历哈希表,而表最大的情况下会容纳整个字符集(及对应下标)。

更新 2.0

  • 比较精简的代码
class Solution {
    public int lengthOfLongestSubstring(String s) {
        // init
        int len = s.length();
        int max = 0;
        char[] arr = s.toCharArray();

        // <字符,字符出现下标>
        Map<Character, Integer> hashmap = new HashMap<>();
        int windowLeft = 0;
        for(int i = 0; i < len; i++) {
            // Case 1 重复
            if(hashmap.containsKey(arr[i])) {
                int index = hashmap.get(arr[i]);
                for(int j = windowLeft; j <= index; j++) {
                    hashmap.remove(arr[j]);
                }
                windowLeft = index + 1;
                hashmap.put(arr[i], i);
            }
            // Case 2 没重复
            else {
                hashmap.put(arr[i], i);
                max = Math.max(max, hashmap.size());
            }
        }
        return max;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值