滑动窗口算法学习(一)

目录

思想

案例

连续元素最大之和

题目

分析

解法

求相同字母异序词的下标

题目

分析

解法

 


思想

滑动窗口是指一个窗口,在一段区间上从左到右滑动,一直到区间的尾部,滑动窗口的长度是可以动态变化的(也可以固定)。一般情形下可以使用两个指针分别指向窗口的两边,指针 i 指向窗口的左边界,指针 j 指向窗口的右边界

一些情况下,使用滑动窗口处理字符串和数组 能提高效率,减少循环的嵌套使用,降低时间复杂度

滑动窗口在网络、大数据、流量控制等都有应用。

下面将简单介绍使用滑动窗口处理字符串和数组的案例

案例

连续元素最大之和

题目

有一个整型数组,给定一个正整数k,求数组里连续k个数之和的最大值

Input : arr[] = {100, 200, 300, 400}  k = 2

Output : 700

Input : arr[] = {1, 4, 2, 10, 23, 3, 1, 0, 20}  k = 4

Output : 39

Input : arr[] = {2, 3} k = 3 Output : Invalid 

分析

上述问题能想到的最简单的解法就是遍历整个数组,从下标为0开始,每次循环获取k个连续的元素,计算其和之后比较获得最大的和,这样一来需要两次循环(一层遍历数组,一层遍历k个元素)。

我们可以使用滑动窗口来简化代码,因为k是给定的固定值,所以窗口大小是固定的,相当于窗口向右滑动的时候,只需要减去左侧的值(被移除窗口范围的旧值),再加上右侧的值(新移入窗口范围的元素),就可以得到新的连续K个数之和,遍历之后就能得到最大值,只需要一层遍历就足够了

解法

public void cal(int[] array, int k) {
        if (array.length == 0 || k <= 0 || k > array.length) {
            System.out.println("Invalid");
            return;
        }

        int maxSum = 0;
        //计算初始窗口位置的K个数之和
        for (int i = 0; i < k; i++) {
            maxSum += array[i];
        }

        int windows_sum = maxSum;
        for (int i = 1; i <= array.length - k; i++) {
            windows_sum = windows_sum - array[i - 1] + array[k + i - 1];
            if (windows_sum > maxSum) {
                maxSum = windows_sum;
            }
        }

        System.out.println("result= " + maxSum);

    }

求相同字母异序词的下标

题目

给定一个字符串s,和一个非空字符串p,要求寻找在s中所有和p满足相同字母异序词的子串(s,p全都是由26个小写英文字母组成,并且长度不大于20100),并返回对应的子串的第一个字符的下标

Input: s: "cbaebabacd" p: "abc"

Output: [0, 6]

分析

要求找到相同字母异序词,只需要子串里各个字母的个数相同即可。

1.使用map集合来表示子串,key为26个英文字母,value为每个字母对应的个数

2.使用int数组来表示子串(每个元素表示对应字母的个数,第一个元素表示’a’的个数,第二个表示’b’的个数,以此类推…),每次滑动的时候判断目标窗口和滑动窗口里的int数组是否一致

解法

解法一:

使用map里记录每个子串里的每个字母的元素个数,由于采用判断map是否有该元素的方式来加快遍历速度,故每次判断字母后需要减去1,每结束一次循环判断还需要还原现场(把map还原成初始状态initMap)

 public static List<Integer> findAnagrams(String s, String p) {
        List<Integer> result = new ArrayList<Integer>();
        if (s == null || p == null || p.length() > s.length()) {
            return result;
        }

        Map<Character, Integer> map = new HashMap<Character, Integer>();
        initMap(p, map);

        int windowsLen = p.length();
        //代表左右窗口指针
        int left = 0;
        int right = left + windowsLen - 1;

        while (right < s.length()) {
            boolean flag = true;
            List<Character> list = new ArrayList<Character>();
            for (int i = right; i >= left; i--) {
                char c = s.charAt(i);
                Integer count = map.get(c);
                //i对应的字母不在目标串里,因为两个子串的长度一致,故所有包含i上的字母的子串都不满足条件
                if (count == null || count == 0) {
                    left = i + 1;
                    right = left + windowsLen - 1;
                    flag = false;
                    break;
                } else {
                    map.put(c, map.getOrDefault(c, 0) - 1);
                    //把在比较过程中满足的字母存在list里(因为这里在比较字符串的时候采用相减的方式而不是==)
                    list.add(c);
                }
            }
            //如果退出时,flag表示整个窗口的元素都在map里,说明满足条件
            if (flag == true) {
                result.add(left);
                left++;
                right = left + windowsLen - 1;
            }
            //还原现场,让map的数据保持和p的组成一致
            for (Character c : list) {
                map.put(c, map.getOrDefault(c, 0) + 1);
            }

        }

        return result;
    }

    private static void initMap(String p, Map<Character, Integer> map) {
        map.clear();
        for (char c : p.toCharArray()) {
            map.put(c, map.getOrDefault(c, 0) + 1);
        }
    }

 

解法二:

上述代码比较繁琐,解法二使用int数组,直接比较数组,逻辑上更加清晰

public List<Integer> findAnagrams(String s, String p) {
        List<Integer> ans = new ArrayList<>();
        if (s.length() < p.length()) {
            return ans;
        }

        int[] dict = new int[26];
        //使用26长度的整型数组来表示给定字符串p的组成
        for (char c : p.toCharArray()) {
            dict[c - 'a']++;
        }
        //用来记录滑动窗口里的字符串的组成
        int[] cur = new int[26];
        for (int i = 0; i < p.length() ; i++) {
            cur[s.charAt(i) - 'a']++;
        }

        for (int i = p.length() ; i < s.length(); i++) {
            if (isSame(dict, cur)) {
                ans.add(i - p.length() );
            }
            cur[s.charAt(i - p.length() ) - 'a']--;
            cur[s.charAt(i) - 'a']++;
        }
        return ans;
    }
     //判断两个int数组是否一致
     private boolean isSame(int[] a, int[] b) {
        for (int i = 0; i < 26; i++) {
            if (a[i] != b[i]) {
                return false;
            }
        }
        return true;
    }

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
滑动窗口目标检测算法是一种常见的目标检测方法。该算法的主要思路是通过固定大小的窗口以及固定步长,在需要检测的图片上滑动窗口进行检测。首先需要预先训练卷积网络,将经过裁剪的数据集进行训练。然后将窗口中的图像送入训练好的卷积网络中进行检测,判断窗口中是否存在目标物体,最终可以大致定位物体的位置。该算法的实现过程可以参考吴恩达教程。然而,滑动窗口目标检测算法也存在一定的缺点,即计算成本较高。如果选择较大的步长,可以减少输入卷积网络的窗口数,但是可能会影响性能。相反,如果选择较小的步长,传递给卷积网络的窗口数会增加,这意味着计算成本会增加。因此,在使用滑动窗口目标检测算法时需要权衡计算成本和性能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [卷积滑动窗口检测算法原理](https://blog.csdn.net/weixin_42285271/article/details/87920939)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [【深度学习理论】基于滑动窗口的目标检测算法](https://blog.csdn.net/TwT520Ly/article/details/79471096)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [基于滑动窗口的目标检测](https://blog.csdn.net/weixin_34910922/article/details/118228250)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值