【Review】 数组篇总结 ---二分、双指针、滑动(持续补充新算法)

这篇博客总结了滑动窗口算法在数组问题中的应用,包括水果进篮子的最大连续子数组长度和查找最小覆盖子串。通过使用自定义HashMap类或数组来优化空间和时间复杂度,同时对比了不同数据结构的选择对性能的影响。此外,还提及了简单的字符串搜索问题,如实现strStr()函数,可以通过Java内置方法或KMP算法解决。
摘要由CSDN通过智能技术生成

interview arithmetic

内容管理


数组算法续


滑动窗口的题目总结一下

滑动窗口的题目类似记忆化,就是不回溯,当右指针滑出边界的时候,就移动左指针至

https://leetcode-cn.com/problems/fruit-into-baskets/

 ArrayList kindList = new ArrayList();  这里达不到目的的,没有remove方法,使用Counter类,不是java类库中的,如果普通项目使用,要导入com.codahale.metrics
       Set kindList = new HashSet<>();

所以最佳的集合还是使用Map最好,Map的键用来存储水果的种类,值用来存储水果的数量;因为每次遇到相同的键就要进行刷新,所以还是使用Map

但是这里的Map应该进行处理,使用内部类自定义一个HashMap,重写get方法,当键不存在的时候,返回0,而不是null; 并且加入add方法,add的时候就自动将现在的值进行加减操作

class Solution {
    public int totalFruit(int[] fruits) {
        int start = 0, end = 0;
        int max = 0;
        Counter kindList = new Counter();
        while(end < fruits.length) {
            //加入,键是Set,会去重,但是值记录了个数
            kindList.add(fruits[end],1); 
            while(kindList.size() > 2) { //可以简单将滑动窗口当作一个弹性窗口,一直满足条件,先右边动,左边固定的时候左边动
                //移除start位置的元素
                kindList.add(fruits[start],-1);//减少一个数量
                if(kindList.get(fruits[start])  == 0){
                    kindList.remove(fruits[start]);
                }
                start ++;
            }
            //每次满足的时候记录
            max = Math.max(max,end + 1 - start);
            end ++;
        }
        return max;
    }

    class Counter extends HashMap<Integer,Integer> {
        //重写方法,就是获取元素的时候,如果没有,那么就是0,不是null
        public int get(int k) {
            return this.containsKey(k) ? super.get(k) : 0;
        }
        //add的时候是直接为value算术运算
        public void add(int k, int v) {
            this.put(k,this.get(k) + v); //每次插入的时候,因为是Set,就会自动更新值
        }
    }
}

这里的思路和之前的那道滑动窗口一样,都是弹性的窗口,end先跑,然后当不满足条件的时候,就移动start直到满足条件

这里可以不使用Map,因为创建对象、实例化Map需要时间

class Solution {
    public int totalFruit(int[] fruits) {
        int start = 0, end = 0;
        int max = 0;
        //这里水果种类是有限的,所以还是使用空间换时间
        int count = 0;//水果种类
        int[] kindList = new int[fruits.length];
        //进行遍历
        while(end < fruits.length) {
            kindList[fruits[end]] ++; //数量增加 ,java会自动进行初始化
            if(kindList[fruits[end]] == 1) {
                //说明是新的,只有等于1的才是刚加上的
                count ++;
            }
            while(count > 2) {
                //移除start
                kindList[fruits[start]] --;
                if(kindList[fruits[start]]  == 0) count --;
                start ++;
            }
            max = Math.max(max,end + 1 -start);
            end ++;
        }
        return max;
    }
}

这里就是使用了数组来代替上面的HashMap来存储数据,这样子虽然空间复杂度为O(N),但是执行时间下降,不需要自定义一个Map,时间从72ms到7ms

这里再介绍一个类似的滑动窗口的题目

76. 最小覆盖子串 - 力扣(LeetCode) (leetcode-cn.com)

这里的题目还是比上面难一点,但是思路都是使用数组的pos代表种类,value代表数量

class Solution {
  
    public String minWindow(String s, String t) {
      //这个题和上面的菜篮问题相同,我们可以直接选择一个数组来作为存储种类的数据,数组pos代表种类,值代表个数
      //char是8位的,那么字符就可以转换位整型,就是2^7 = 128
       char[] chars = s.toCharArray(), chart = t.toCharArray();
       //典型的滑动窗口,最开始先将所有的t中的字符串给挖坑,这样子方便比较呢,当满足条件的时候,如果第一个字符就是目标字符,那么久等到下一次找到字符的时候再移动,要保证一直满足条件
       int[] kindList = new int[128];
       int start = 0, end = 0, cnt = 0;
       String res = "";
       //挖坑
       for(char c : chart) kindList[c]--;
       //开始找滑动窗口
       while(end < chars.length) {
           kindList[chars[end]] ++;
           if(kindList[chars[end]] <= 0) {
               cnt ++;
           }
           //满足条件了,并且要找到新的满足条件的序列【替代品】的时候才移动start,不然乱了
           while(cnt == chart.length && kindList[chars[start]] > 0) {
               kindList[chars[start]]--;
               start ++;
           }
           //判断
           if(cnt == chart.length) {
               if(res.equals("") || res.length() > end + 1 - start) {
                    res = s.substring(start,end + 1);
                }
           } 
           end ++;
       }
       return res;
    }
}

28. 实现 strStr() - 力扣(LeetCode) (leetcode-cn.com)

这个题目再来说一下,那天过于忙碌,实际上就是很简单,首先可以使用java自带的方法indexOf,就可以了

class Solution {
    public int strStr(String haystack, String needle) {
        return haystack.indexOf(needle);
    }
}

一行代码就解决了。。。。。,但是自己手撕的话,除了克鲁德之外,最佳的算法就是KMP了

class Solution {
    public int strStr(String haystack, String needle) {
        int n = haystack.length(), m = needle.length();
        if (m == 0) {
            return 0;
        }
        int[] pi = new int[m];
        for (int i = 1, j = 0; i < m; i++) {
            while (j > 0 && needle.charAt(i) != needle.charAt(j)) {
                j = pi[j - 1];
            }
            if (needle.charAt(i) == needle.charAt(j)) {
                j++;
            }
            pi[i] = j;
        }
        for (int i = 0, j = 0; i < n; i++) {
            while (j > 0 && haystack.charAt(i) != needle.charAt(j)) {
                j = pi[j - 1];
            }
            if (haystack.charAt(i) == needle.charAt(j)) {
                j++;
            }
            if (j == m) {
                return i - m + 1;
            }
        }
        return -1;
    }
}

这样就优化了很多,这篇博客将作为数组专题的总结,随时更新🎉

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值