美文网首页
滑动窗口 双端队列

滑动窗口 双端队列

作者: Rumbles | 来源:发表于2019-04-23 07:37 被阅读0次

    双端队列:双端队列是限定插入和删除操作在表的两端进行的线性表。这两端分别称做端点1和端点2:简单来说就是前端和尾端都可以删除或者插入

    只便利了一次 减去旧值得 加上新值 得到新的和

    只要是子串 子数组 就可以使用此算法

    重点是走了一个值。再来了一个值 查找子串

    要检查一个字符是否已经在子字符串中,我们可以检查整个子字符串,这将产生一个复杂度为 O(n2)的算法,但我们可以做得更好。通过使用 HashSet 作为滑动窗口,我们可以用 O(1) 的时间来完成对字符是否在当前的子字符串中的检查。

    采取了滑动窗口技术(思路),消除或者减少【求最大值还是需要少量的循环】内部循环

    package com.cdfive.learn2018.algorithm;
    
    /**
     * 求数组array长度为k的子数组的最大和
     *
     * 算法1-cal
     * 遍历所有子数组,求和并比较
     * 嵌套循环 O(n*k)
     *
     * 算法2-calByLeapWinow
     * 窗口向右滑动,减去失效值加上最新值
     * 单层循环 O(n)
     *
     * input:  array=[1,2,3,4] k=2
     * output: 7 // 3+4
     *
     * input:  array=[-1,4,7,-3,8,5,-2,6] k=3
     * output: 12 // 7-3+8
     *
     * @author cdfive
     * @date 2018-12-02
     */
    public class SimpleLeapWindow1 {
    
        public static void main(String[] args) {
            cal(new int[]{1, 2, 3, 4}, 2);
            cal(new int[]{-1,4,7,-3,8,5,-2,6}, 3);
    
            System.out.println("-------------");
    
            calByLeapWinow(new int[]{1, 2, 3, 4}, 2);
            calByLeapWinow(new int[]{-1,4,7,-3,8,5,-2,6}, 3);
        }
    
        /**
         * 遍历所有子数组,求和并比较
         * 嵌套循环 O(n*k)
         */
        public static void cal(int[] array, int k) {
            if (array.length == 0 || k <= 0 || k > array.length) {// 非法参数不处理
                return;
            }
    
            int index = 0;// 记录最大子数组第1个元素的索引,目前是0
            int maxSum = 0;// 记录最大子数组和,目前是从左开始第1个子数组
            for (int i = 0; i < k; i++) {
                maxSum += array[i];
            }
    
            for (int i = 1; i <= array.length - k; i++) {// 遍历所有子数组,求和并比较
                int curSum = 0;
                for (int j=0; j < k; j++) {// 计算当前子数组和
                    curSum += array[i + j];
                }
                if (curSum > maxSum) {// 如果大于最大和,则记录
                    maxSum = curSum;
                    index = i;
                }
            }
    
            /**打印结果*/
            System.out.print(maxSum + " // ");// 打印最大和
            System.out.print(array[index]);// 先打印第1个值
            for (int i = 1; i < k; i++) {
                int value = array[i + index];
                System.out.print(value >= 0 ? ("+" + value) : value);// 非负数前面打印+号
            }
            System.out.println();
        }
    
        /**
         * 窗口向右滑动,通过减失效值加最新值求和并比较
         * 单层循环 O(n)
         */
        public static void calByLeapWinow(int[] array, int k) {
            if (array.length == 0 || k <= 0 || k > array.length) {// 非法参数不处理
                return;
            }
    
            int index = 0;// 记录最大子数组第1个元素的索引,目前是0
            int maxSum = 0;// 记录最大子数组和,目前是从左开始第1个子数组
            for (int i = 0; i < k; i++) {
                maxSum += array[i];
            }
    
            int curWindowSum = maxSum;
            for (int i = 1; i <= array.length - k; i++) {// 从下个元素开始,即窗口向右滑动
                curWindowSum = curWindowSum - array[i - 1] + array[k + i - 1];// 减去失效值,加上最新值
                if (curWindowSum > maxSum) {// 如果大于最大和,则记录
                    maxSum = curWindowSum;
                    index = i;
                }
            }
    
            /**打印结果*/
            System.out.print(maxSum + " // ");// 打印最大和
            System.out.print(array[index]);// 先打印第1个值
            for (int i = 1; i < k; i++) {
                int value = array[i + index];
                System.out.print(value >= 0 ? ("+" + value) : value);// 非负数前面打印+号
            }
            System.out.println();
        }
    }
    

    有一个整型数组 arr 和一个大小为 w 的窗口从数组的最左边滑到最右边,窗口每次向右边滑一个位置。 返回一个长度为n-w+1的数组res,res[i]表示每一种窗口状态下的最大值。 以数组为[4,3,5,4,3,3,6,7] 那么输出5 5 5 4 6 7

    设置一个保存下标的数组qIndex
    
    有如下规则
    队尾放入规则:循环原数组 把小于的放入 qIndex队尾。如果大于等于那么弹出 qIndex队尾数据 直到某个值大于我们才放入队尾。【需要循环】
    队头 弹出规则:过期的:【我猜想这就是为啥放入下标的原因】
    
    
    

    相关文章

      网友评论

          本文标题:滑动窗口 双端队列

          本文链接:https://www.haomeiwen.com/subject/drmwyqtx.html