您好,欢迎来到爱站旅游。
搜索
您的当前位置:首页数据结构与算法-滑动窗口练习

数据结构与算法-滑动窗口练习

来源:爱站旅游

长度最小的子数组(209)

方法一:暴力求解(效率差):
使用两个 for 循环,一个 for 循环固定一个数字比如 m,另一个 for 循环从 m 的下一个元素开始累加,当和大于等于 s 的时候终止内层循环,顺便记录下最小长度


    public int minSubArrayLen(int s, int[] nums) {
        int min = Integer.MAX_VALUE;
        for (int i = 0; i < nums.length; i++) {
            int sum = nums[i];
            if (sum >= s)
                return 1;
            for (int j = i + 1; j < nums.length; j++) {
                sum += nums[j];
                if (sum >= s) {
                    min = Math.min(min, j - i + 1);
                    break;
                }
            }
        }
        return min == Integer.MAX_VALUE ? 0 : min;
    }

方法二:滑动窗口,使用双指针,left和right,分别用来向右缩小窗口和向右扩大窗口
思路:遇到题目求最小,可思考先预设一个最大值,然后不断更新
窗口包含数值总和大了就向右缩小窗口,小了就向右扩展窗口,不断试错,直至找到最小窗口,并且使所有值加起来超不过target
注意前后顺序

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int left = 0;       
        int sum = 0;
        int result = Integer.MAX_VALUE;//让窗口最大,这样就能不断更新最小值窗口
        for(int right = 0;right < nums.length ;right++){
            sum += nums[right];
            while(sum >= target){
                
                result = Math.min(result, right - left + 1);//让窗口永远保持最小
                sum -= nums[left++];//左侧索引前移
                
                
            }           
        }
        //依照案例,如果所有值加起来都小于target,返回0,也就是MAX_VALUE一直都没变过
        return result == Integer.MAX_VALUE ? 0 : result;

    }
}

找到字符串中所有字母异位词(438)

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> ans = new ArrayList<>();
        int m = s.length();
        int n = p.length();

        if (m < n) {
            // 如果s没p长,直接返回空列表
            return ans;
        }

        int[] sCnt = new int[26];
        int[] pCnt = new int[26];
        
        for (int i = 0; i < n; i++) {
            sCnt[s.charAt(i) - 'a']++;
            pCnt[p.charAt(i) - 'a']++;
        }

        if (Arrays.equals(sCnt, pCnt)) {
            // 初始窗口就相等
            ans.add(0);
        }

        for (int i = 0; i < m - n; i++) {
            // 窗口右移
            sCnt[s.charAt(i) - 'a']--;
            sCnt[s.charAt(i + n) - 'a']++;

            if (Arrays.equals(sCnt, pCnt)) {
                ans.add(i + 1);
            }
        }

        return ans;
    }
}

最小覆盖子串(76)

 public String minWindow( String s, String t ) {
        String res = "";
        if ( t.length() > s.length() ) {
            return res;
        }

        HashMap<Character, Integer> need = new HashMap<>();
        HashMap<Character, Integer> window = new HashMap<>();

        for ( int i = 0; i < t.length(); i++ ) {
            char ch = t.charAt( i );
            need.put( ch, need.getOrDefault( ch, 0 ) + 1 );
        }
        int l = 0;
        int r = 0;
        int valid = 0;
        int len = Integer.MAX_VALUE;
        int start = 0;
        while ( r < s.length() ) {
            char ch = s.charAt( r );
            r++;
            if ( need.containsKey( ch ) ) {
                window.put( ch, window.getOrDefault( ch, 0 ) + 1 );
                if ( window.get( ch ).equals( need.get( ch ) ) ) {
                    valid++;
                }
            }
            // 判断左侧窗口是否要收缩
            while ( valid == need.size() ) {
                // 在这里更新最小覆盖子串
                if ( r - l < len ) {
                    start = l;
                    len = r - l;
                }
                // d 是将移出窗口的字符
                char d = s.charAt( l );
                // 左移窗口
                l++;
                // 进行窗口内数据的一系列更新
                if ( need.containsKey( d ) ) {
                    if ( window.get( d ).equals( need.get( d ) ) ) {
                        valid--;
                    }
                    window.put( d, window.get( d ) - 1 );
                }
            }
        }
        return len == Integer.MAX_VALUE ? "" : s.substring( start, start+len );
    }

字符串的排列(567)

要注意什么时候向右扩大窗口,什么时候向右缩小窗口,什么时候结算窗口内的信息,如何更新窗口内的信息

class Solution {
    public boolean checkInclusion(String s1, String s2) {
        int l=0;
        int r=0;
        
        int []s1arr=new int[26];
        int []s2arr=new int[26];
        for(int i=0;i<s1.length();i++){
            s1arr[s1.charAt(i)-'a']++;
        }
        while(r<s2.length()){
            s2arr[s2.charAt(r)-'a']++;
            
            if(r-l+1==s1.length()){
               if(equalS1S2(s1arr,s2arr)) {
                   return true;
               }else{
                s2arr[s2.charAt(l)-'a']--;
                l++;
               }  
            }
            r++;//r++位置要放好,不能直接放在s2arr[s2.charAt(r)-'a']++;下面
        }
        return false;
    }
    public  boolean equalS1S2( int[] s1,int[] s2){
        for(int i=0;i<s1.length;i++){
            if(s1[i]!=s2[i])return false;     
        }
        return true;

    }
}

无重复字符的最长子串(3)

使用set,让left每次加一

/*时间复杂度:O(2n) = O(n),最坏的情况是 left 和 right 都遍历了一遍字符串*/
	/*空间复杂度:O(n)*/
	/*https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/jian-dan-yi-dong-javac-pythonjshua-dong-bff20/*/
	public int lengthOfLongestSubstring2(String s) {
	    int n = s.length();
	    if (n <= 1) return n;
	    int maxLen = 1;

	    int left = 0, right = 0;
	    /*使用set集合记录窗口中出现的字符,这样可以保证 不重复,
	     *如果窗口中不包含右指针指向的字符,就把它加入set(并记录窗口最大值 ),如果存在就移除 ,并将left指针++,每次移动一次*/
	    Set<Character> window = new HashSet<>();
	    while (right < n) {
	        char rightChar = s.charAt(right);
	        while (window.contains(rightChar)) {
	            window.remove(s.charAt(left));
	            left++;
	        }
	        maxLen = Math.max(maxLen, right - left + 1);
	        window.add(rightChar);
	        right++;
	    }

	    return maxLen;
	}

使用map,记录每个字符的索引,遇到重复字符时,直接跳到 重复字符的下一个 位置

/*上面的方法,出现重复字符时,是一个一个字符的缩小窗口
*可以通过map记录每个字符在字符串中出现的位置,当遇到重复字符时,把left指针跳到重复字符的下一个位置 */
/*/*力扣3,评论区
 * https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/wu-zhong-fu-zi-fu-de-zui-chang-zi-chuan-by-leetc-2
 * */*/
	 public static int lengthOfLongestSubstringWithoutRepeatingCharacters(String s) {
	        int len = s.length();

	        Map<Character, Integer> index = new HashMap<>();

	        int max = 0;
	        int left = 0;
	        for (int right = 0; right < len; right++) {
	            char c = s.charAt(right);
	            if (index.containsKey(c)) {
	                int lastIndex = index.get(c);
	                if (lastIndex + 1 > left) {
	                    left = lastIndex + 1;
	                }
	            }
	            //因为左指针已经跳到重复字符的下一个位置了,当前右指针指向的字符跟去掉的字符一样,所以需要在map中更新一下位置	
	            index.put(c, right);
	            max = Math.max(max, right - left + 1);
	        }

	        return max;
	    }
	 

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- azee.cn 版权所有 赣ICP备2024042794号-5

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务