力扣209题,牛客90(滑动窗口)

209、长度最小的子数组

基本思想:

滑动窗口

具体实现:

1.窗口内是什么?

窗口内是窗口起始位置和窗口结束位置框住的一段数组。

2.窗口的起始位置如何移动?

如果当前窗口的值>=s,窗口要缩小,就是起始位置向后移。

3.窗口的结束位置如何移动?

如果当前窗口的值<s,窗口要扩大,就是结束位置向后移。

 

 

 

 

代码:

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++){//如果当前窗口的值<s,窗口要扩大,就是结束位置向后移。
            sum += nums[right];
            while (sum >= target){
                result = Math.min(result,right - left + 1);//找长度最小的
                sum -= nums[left++];//如果当前窗口的值>=s,窗口要缩小,就是起始位置向后移。
            }
        }//如果当前窗口的值<s,窗口要扩大,就是结束位置向后移。
        return result == Integer.MAX_VALUE ? 0 : result;
    }
}

 

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int sum = 0;
        int left = 0, right = 0;
        int count = Integer.MAX_VALUE;
        while (right < nums.length) {
            sum += nums[right++];
            while (sum >= target) {
                count = Math.min(count, right - left);
                sum -= nums[left++];
            }
        }
        return count == Integer.MAX_VALUE ? 0 : count;
    }
}

 

 

牛客90 最小覆盖子串

这道题的思路是:
1) begin开始指向0, end一直后移,直到begin - end区间包含T中所有字符。
记录窗口长度d
2) 然后begin开始后移移除元素,直到移除的字符是T中的字符则停止,此时T中有一个字符没被
包含在窗口,
3) 继续后移end,直到T中的所有字符被包含在窗口,重新记录最小的窗口d。
4) 如此循环知道end到S中的最后一个字符。
时间复杂度为O(n)
public class Solution {
    public String minWindow(String S, String T) {
        int[] map = new int[128];
        //init map, 记录T中每个元素出现的次数
        for(int i = 0; i < T.length(); i++) {
            map[T.charAt(i)]++;
        }

        // begin end两个指针指向窗口的首位,d记录窗口的长度, counter记录T中还有几个字符没被窗口包含
        int begin = 0, end = 0, d = Integer.MAX_VALUE, counter = T.length(), head = 0;
        // end指针一直向后遍历
        while(end < S.length()) {
            // map[] > 0 说明该字符在T中出现,counter-- 表示对应的字符被包含在了窗口,counter--, 如果s中的字符没有在T中出现,则map[]中对应的字符-1后变为负值
            if(map[S.charAt(end++)]-- > 0) {
                counter--;
            }
            // 当counter==0时,说明窗口已经包含了T中的所有字符
            while (counter == 0) {
                if(end - begin < d) {
                    d = end - (head = begin);
                }
                if(map[S.charAt(begin++)]++ == 0) {  // begin开始后移,继续向后寻找。如果begin后移后指向的字符在map中==0,表示是在T中出现的,如果没有出现,map[]中的值会是负值。
                    counter++;                      // 在T中的某个字符从窗口中移除,所以counter++。
                }
            }
        }
        return d==Integer.MAX_VALUE ? "" :S.substring(head, head+d);
    }
}

 

import java.util.*;

public class Solution {
    /**
     * 
     * @param S string字符串 
     * @param T string字符串 
     * @return string字符串
     */
    public String minWindow (String s, String t) {
        HashMap<Character, Integer> window = new HashMap<>();
        HashMap<Character, Integer> need = new HashMap<>();
        for (int i = 0; i < t.length(); i++) {
            Integer count = need.get(t.charAt(i));
            count = count == null ? 1 : ++count;
            need.put(t.charAt(i),count);
        }
        int left =0 , right = 0;
        int vaild = 0;
        int len = Integer.MAX_VALUE,start = 0;
        //最小覆盖字串起始索引
        while (right < s.length()){
            char c = s.charAt(right);
            right++;
            if (need.containsKey(c)){
                Integer count = window.get(c);
                count = count == null ? 1 : ++count;
                window.put(c,count);
                if (window.get(c).equals(need.get(c))){
                    vaild++;
                }
            }

            //都包含了,right找到了,可以考虑收缩
            while (vaild == need.size()){
                if (right -left < len){
                    start = left;
                    len = right - left;
                }
                //d是将要移出窗口的字符
                char d = s.charAt(left);
                //左移窗口
                left++;
                //数据更新
                if (need.containsKey(d)){
                    if (window.get(d).equals(need.get(d))){
                        vaild--;
                    }
                    window.put(d,window.get(d)-1);
                }
            }
        }
        return len == Integer.MAX_VALUE ? "" : s.substring(start,start+len);
    }

 

 

posted @ 2021-10-10 15:39  最近饭吃的很多  阅读(42)  评论(0编辑  收藏  举报