滑动窗口基础问题

309 阅读3分钟

程序员必备小知识

滑动窗口法,也叫尺取法(可能也不一定相等,大概就是这样 =。=),可以用来解决一些查找满足一定条件的连续区间的性质(长度等)的问题。由于区间连续,因此当区间发生变化时,可以通过旧有的计算结果对搜索空间进行剪枝,这样便减少了重复计算,降低了时间复杂度。往往类似于“请找到满足xx的最x的区间(子串、子数组)的xx”这类问题都可以使用该方法进行解决。

无重复的最长字串

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

输入: s = "abcabcbb"

输出: 3

解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

因为我之前做过类似的题目,我最开始的想法是利用ASLL码,将字符转成对应数字,对应数组的坐标,利用数组存储改字符串的出现的个数,但是在实现的过程中,我发现了在字符转转化的过程中,还是非常的麻烦的,于是我想到了一种数据结构,哈希表,使用哈希表我们就不需要考虑这些问题

我们结合双指针,我们右指针不断向前遍历,将遍历到元素存入哈希表中,当哈希表中遇到重复元素时,做指针开始移动,移动到重复元素的下一位停止,右指针再一次开始运动。

public int lengthOfLongestSubstring(String s) {
        Set<Character> a=new HashSet<>();
        int n=s.length();
        int right=0,max=0;
        for (int i=0;i<n;i++){
            if(i!=0){
                a.remove(s.charAt(i-1));
            }
            while (right < n && !a.contains(s.charAt(right))){
                a.add(s.charAt(right));
                right++;
            }
            max=Math.max(max,right-i);
        }
        return max;
    }

字符串的排列

给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。换句话说,s1 的排列之一是 s2 的 子串 。

要求:

1 <= s1.length, s2.length <= 104

s1 和 s2 仅包含小写字母

输入:s1 = "ab" s2 = "eidbaooo"

输出:true

解释:s2 包含 s1 的排列之一 ("ba").

输入:s1= "ab" s2 = "eidboaoo"

输出:false

这道题最开始的时候还是让我想到了我上一道题的解法,利用数组的坐标来表示元素,因为他的限定条件是仅包含小写字母,我们利用ASLL的值可以很好的表示元素。

题目中要求的是子串,就存在排列的影响,子串排列的种类太多了,但是正因为是子串,只要我们存在的元素种类,个数都相同,我们就可以判断他们是相同的,只是排列的顺序不同。

 public boolean checkInclusion(String s1, String s2) {
        int [] num1=new int[26];
        int [] num2=new int[26];
        if((s2.length()-s1.length())<0){
            return false;
        }
     //我们先获取s1的长度的数组,去判断他们的起始头部是否相同
        for(int i=0;i<s1.length();i++){
            num1[s1.charAt(i)-'a']++;
            num2[s2.charAt(i)-'a']++;
        }
        if(Arrays.equals(num1,num2)){
            return true;
        }
     //再利用滑动窗口,窗口长度固定,不断滑动,判断窗口中元素是否符合要求
        for(int i=s1.length();i<s2.length();i++){
            //添加新的元素
           num2[s2.charAt(i)-'a']++;
            //删除窗口中第一位元素
           num2[s2.charAt(i-s1.length())-'a']--;
            if(Arrays.equals(num1,num2)){
                return true;
            }
        }
        return false;
    }

因为将字母存入数组,所以我们只需判断数组中元素是否一样我们就知道,字符串是否一样了。

用数组的坐标表示元素,数组存储元素个数,我也忘记了是从哪学到了,但是我一直没用忘记这种用法,自己用起来还是很方便的。