同向双指针(滑动窗口)算法

209. 长度最小的子数组

这里的更新结果就题来定

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
           int sum = 0;
           int len = 0;
           int f = 0;
            for(int left = 0, right = 0; right < nums.length;){
                //求和
               sum += nums[right];
               while(sum >= target){
                //len
                int t = right - left + 1; 
                if(f == 0 ){
                    len = t;
                }
                if(t < len ){
                     len = right - left +1;
                }
                f = 1;

                left++;
                // if(left >= nums.length){
                //     break;
                // }
                sum -= nums[left-1];
               }
                //if(right < nums.length){
                    right++;
                //}
                // if(left == nums.length){
                //     break;
                // }
                
            }
            return len;
    }
}

我在处理第一次len得到长度时使用的flag,老师用的时最大值,思路可以借鉴

 

先暴力枚举分析所有情况,做这种题都要这样。根据枚举优化得到滑动窗户做法 

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

 

class Solution {
        public int lengthOfLongestSubstring(String s) {
        Set<Character> set = new HashSet<Character>();
        int n = s.length();
        int len = 0;
        for(int left = 0, right = 0; right < n;right++){


                while(right > 0 && set.contains(s.charAt(right))){
                    set.remove(s.charAt(left));
                    left++;
                }
            set.add(s.charAt(right));
            len = Math.max(len, right -left +1);

        }
        return len;
    }
}

什么时候更新len有点难,多想一下过程的思路 

 

这里用数组来当hash,空间复杂度为O(1),但如果new hash 就是O(N)

1004. 最大连续1的个数 III

 

 虽然是两层循环,但时间复杂度时O(N),空间复杂度O(1)

1658. 将 x 减到 0 的最小操作数

class Solution {
  public int minOperations(int[] nums, int x) {
        int s= 0;
        for(int i = 0; i< nums.length; i++){
            s += nums[i];
        }
        int target = s - x, len = 0;
        if(target == 0){
            return nums.length;
        }
        if(target < 0){
            return -1;
        }
        int f = 0;
        for(int left = 0, right = 0, sum = 0; right < nums.length; right++ ){
            sum += nums[right];
            while(sum >= target){
                if(sum == target){
                    len = Math.max(len, right - left + 1);
                    sum -= nums[left];
                     left++;
                    f = 1;
                }else{
                    sum -= nums[left];
                    left++;
                }

            }
        }
        return f == 1 ? nums.length - len : -1;
    }
}

如果数组中有0 负数就不能用滑动窗口

 904. 水果成篮

class Solution {
 public static int totalFruit(int[] fruits) {
        Map<Integer,Integer> hasH = new HashMap<Integer,Integer>();
        int len = 0;
        for(int left = 0, right = 0; right < fruits.length; right++){
            hasH.put(fruits[right],hasH.getOrDefault(fruits[right],0)+1);

            while(hasH.size() > 2){
                hasH.put(fruits[left],hasH.getOrDefault(fruits[left],0)-1);

                left++;
                if(hasH.get(fruits[left-1]) == 0){
                    hasH.remove(fruits[left-1]);
                }
            }
            if(hasH.size() <= 2){
                len = Math.max(len,right - left +1);
            }
        }
        return len;
    }
}

因为水果的范围没有超过int 可以使用数组,这样减少队Hash的调用,时间复杂度会大大的变小 

 

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

class Solution {
 public List<Integer> findAnagrams(String s, String p) {
        List<Integer> List = new ArrayList<>();
        int[] HashP = new int[26];
        int l = p.length();
        if(s.length() < p.length()){
            return List;
        }
        for(int i = 0 ; i < p.length(); i++){
            HashP[p.charAt(i) - 97]++;
        }
        int count = 0;
        int[] HashS = new int[26];
        for(int left = 0, right = 0; right < s.length(); right++){
            while (count < l){
                HashS[s.charAt(right)-97]++;
                count++;
                if(count == l){
                    break;
                }
                right++;
            }
            int f = 1;
            for (int j = 0; j < 26; j++){
                if(HashS[j] != HashP[j]){
                    f = 0;
                    break;
                }
            }
            if( f == 0){
                HashS[s.charAt(left)-97]--;
                count--;
                left++;
            }else {
                List.add(left);
                HashS[s.charAt(left)-97]--;
                count--;
                left++;
            }
        }
        return List;
    }
}

复盘:

第一次:

class Solution {
  public List<Integer> findAnagrams(String ss, String pp) {
        List<Integer> ret = new ArrayList<>();
        char[] s = ss.toCharArray();
        char[] p = pp.toCharArray();
        //new pp Hash1
        int[] Hash1 = new int[26];
        int kinds = 0;
        for(char ch: p){
            if(Hash1[ch-97] == 0){
                kinds++;
            }
            Hash1[ch-97]++;
        }
        //窗口长度
        int len = pp.length();
        int[] Hash2 = new int[26];
        //窗口中有效字符个数
        int count = 0;
        for(int left = 0, right = 0; right < ss.length(); right++){
            //入窗口 in 种类
            char in = ss.charAt(right);
            Hash2[in - 97]++;
            if(Hash2[in - 97] <= Hash1[in - 97]){
                count++;
            }
            //判断
            while(right - left + 1 >= len){
                if(count == pp.length() && right -left + 1 == len){
                    ret.add(left);
                }
                //出窗口 Hash[left]--; left ++
                char out = ss.charAt(left);
                if(Hash2[out - 97] <= Hash1[out - 97]){
                    count--;
                }
                Hash2[out - 97]--;
                left++;
            }

        }
        return ret;
    }
}

30. 串联所有单词的子串

 

复盘:

第一次:

class Solution {
        public List<Integer> findSubstring(String s, String[] words) {
        List<Integer> ret = new ArrayList<>();
        Map<String,Integer> Hash1 = new HashMap<>();
        for(String str: words){
            Hash1.put(str,Hash1.getOrDefault(str,0)+1);//存储words
        }
        //  字符上总长度 单个字符串长度
        int L = words.length,len = words[0].length();

        for(int i = 0; i < len; i++){
            Map<String,Integer> Hash2 = new HashMap<>();
            int count = 0;
            for(int left = i, right = i; right <= s.length() - len; right += len){
                //进窗口
                String in = s.substring(right,right+len);
                Hash2.put(in,Hash2.getOrDefault(in,0)+1);
                if(Hash2.get(in) <= Hash1.getOrDefault(in,0)){
                    count++;
                }
                //判断
                //更新

                //出窗口
                while(right + len - left  >= L*len){
                    if(L == count && right + len - left  == L*len){
                        ret.add(left);
                    }
                    String out = s.substring(left,left+len);
                    if(Hash2.get(out) <= Hash1.getOrDefault(out,0)){
                        count--;
                    }
                    Hash2.put(out,Hash2.get(out)-1);
                    left += len;

                }
            }
        }
        return ret;
    }
}

right是截取的边界,所以要加=

76. 最小覆盖子串

class Solution {
       public String minWindow(String ss, String tt) {
        String ret = "";
        char[] s = ss.toCharArray();
        char[] t =tt.toCharArray();
        if(ss.length() < tt.length()){
            return ret;
        }
        Map<Character,Integer> Hash1 = new HashMap<>();//存储tt
        for(char str : t){
            Hash1.put(str,Hash1.getOrDefault(str,0)+1);
        }
        Map<Character,Integer> Hash2 = new HashMap<>();//窗口
        int count = 0; //容器有效的
        int f = 0;
        for(int left = 0, right = 0; right < s.length; right++){//进窗口 维护 count
            char in = s[right];
            Hash2.put(in,Hash2.getOrDefault(in,0)+1);
            if(Hash2.get(in) == Hash1.getOrDefault(in,0)) {
                count++;
            }
            //判断
            while(count == Hash1.size()){
               //更新 subString 
               if(ss.substring(left,right+1).length() < ret.length() && f == 1){
                    ret = ss.substring(left,right+1);
                }else if(f == 0){
                    f = 1;
                    ret = ss.substring(left,right+1);

                }
                //出窗口 维护count
                char out = s[left];
                if(Hash2.get(out) == Hash1.getOrDefault(out,0)){
                    count--;
                }
                Hash2.put(out,Hash2.get(out)-1);
                left++;
            }
            
        }
        return ret;
    }
}
class Solution {
    public String minWindow(String ss, String tt) {
        String ret = "";
        char[] s = ss.toCharArray();
        char[] t = tt.toCharArray();
        int[] Hash1 = new int[128];//记录tt
        int[] Hash2 = new int[128];//窗口
        //记录tt中的字符 //记录字符的种类
        int kinds = 0;
        for(char str: t){
            if(Hash1[str] == 0)kinds++; 
            Hash1[str]++;
        }
        int f = 0,count = 0; 
        for(int left = 0, right = 0; right < ss.length(); right++){
            //进窗口 //种类
            int in = s[right];
            Hash2[in]++;
            if(Hash2[in] == Hash1[in]) count++; 
            //判断//更新//出窗口
            while(count == kinds){
                if(ss.substring(left,right+1).length() < ret.length() && f == 1){
                    ret = ss.substring(left,right+1);
                }else if(f == 0){
                    f = 1;
                    ret = ss.substring(left,right+1);

                }
                int out = s[left];
                if(Hash2[out] == Hash1[out]) count--;
                Hash2[out]--;
                left++;
            }
            
        }
        return ret;
    }
}

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值