算法入门第6天-滑动窗口(中等2个)

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

1.1 题目描述

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

示例 1:

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

示例 2:

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

示例 3:

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

示例 4:

输入: s = “”
输出: 0

示例 5: 提交错误看到的

输入: s = “dvdf”
输出: 3

提示:

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

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

1.2 代码实现

思路:设置左右指针i和j模拟滑动窗口,当j指向的元素和窗口里没有重复时,j指针右移,同时将元素加入set;当发生重复时,i指针右移,同时从set中删除指向的元素,直至i指针指向重复元素的下一个元素。

我的提交:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if(s.length() < 2){
            return s.length();
        }
        int i = 0, j = 1;
        int maxLen = 1;
        Set<Character> set = new HashSet<>();
        set.add(s.charAt(i));
        while(i <= j && j < s.length()){
            char temp = s.charAt(j);
            if(set.contains(temp)){
                maxLen = Math.max(maxLen, j - i);
                //删除重复字符之前的字符
                while(s.charAt(i) != temp){
                    set.remove(s.charAt(i));
                    i++;
                }
                //删除重复字符
                set.remove(s.charAt(i));
                i++;
            }else{
                set.add(temp);
                j++;
            }
        }
        //与最后一个子串比较
        return Math.max(maxLen, set.size());
    }
}

时间:O(n);空间:O(m);
收获:看到重复想到用 散列表 来判断,看到 子串 涉及放缩,想到可能用 滑动窗口。

做了第3遍,请牢记这道题!!!

2. leetcode 567-字符串的排列

2.1 题目描述

给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。

换句话说,第一个字符串的排列之一是第二个字符串的 子串 。

示例 1:

输入: s1 = “ab” s2 = “eidbaooo”
输出: True
解释: s2 包含 s1 的排列之一 (“ba”).

示例 2:

输入: s1= “ab” s2 = “eidboaoo”
输出: False

提示:

1 <= s1.length, s2.length <= 104
s1 和 s2 仅包含小写字母

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

2.2 代码实现

思路:使用一个数组 cnt 记录 s1 和 s2 字符的出现次数之差(相同的字符,对应次数会抵消),使用变量 diff 记录cnt中不为0的数字个数,在滑动窗口的过程中,每次向右滑一格,都会更新diff并判断。

参考官答:

class Solution {
    public boolean checkInclusion(String s1, String s2) {
        int len1 = s1.length();
        int len2 = s2.length();
        if(len1 > len2){
            return false;
        }
        //开辟数组记录字符出现次数
        int[] cnt = new int[26]; 
        //判断初始窗口中s1, s2的前len1个字符是否相等
        for(int i = 0; i < len1; i++){
            //注意这里是 s1字符--,s2字符++,和后面滑动窗口时cnt[x]++,cnt[y]--是一致的
            //即s2进入窗口的字符是++,离开窗口的字符是--
            cnt[s1.charAt(i) - 'a']--;
            cnt[s2.charAt(i) - 'a']++;
        }
        //统计出现不同字符的个数
        int diff = 0;
        for(int c: cnt){
            if(c != 0){
                diff++;
            }
        }
        //判断初始窗口是否符合条件
        if(diff == 0){
            return true;
        }

        //开始滑动窗口
        for(int i = len1; i < len2; i++){
            int x = s2.charAt(i) - 'a'; //进窗口的字符
            int y = s2.charAt(i - len1) - 'a'; //出窗口的字符
            if(x == y){
                continue;
            }else{
                //处理x前判断一下
                if(cnt[x] == 0){
                    diff++;
                }
                //x进入窗口(这里++是和前面s2入窗口++是一致的)
                cnt[x]++;
                //处理x后判断一下
                if(cnt[x] == 0){
                    diff--;
                }

                // y 同理
                if(cnt[y] == 0){
                    diff++;
                }
                //y离开窗口
                cnt[y]--;
                if(cnt[y] == 0){
                    diff--;
                }
            }
            //判断当前窗口是否符合条件
            if(diff == 0){
                return true;
            }
        }
        return false;
    }
}

时间:O(n+m+t),t为开辟数组大小,这里其实常数26; 空间: O(t);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值