• 每日一题 为了工作 2020 0308 第六题



    /**
    * 问题: 生成窗口最大值数组
    * 有一个整形数组array和一个大小为w的窗口从数组最左边滑到最右边,窗口每次向右边滑动一个位置。
    * 例如,数组为[4,3,5,4,3,3,6,7],窗口大小为3时:
    * [4 3 5] 4 3 3 6 7 窗口的最大值是5
    * 4 [3 5 4] 3 3 6 7 窗口的最大值是5
    * 4 3 [5 4 3] 3 6 7 窗口的最大值是5
    * 4 3 5 [4 3 3] 6 7 窗口的最大值是4
    * 4 3 5 4 [3 3 6] 7 窗口的最大值是6
    * 4 3 5 4 3 [3 6 7] 窗口的最大值是7
    *
    * 如果数组的长度为n,窗口大小为w,则一定会生成n-w+1个窗口的最大值
    * 要求实现一个函数
    * 1.输入:整形数组array,窗口大小w
    * 2.输出:一个长度为n-w+1的数组res,res[i]表示每一种窗口状态下的最大值。
    * 3.算法的时间复杂度为O(n)
    * 分析:
    * 本题的关键在于利用双端队列来实现窗口最大值的更新。首先生成双端队列qmax,qmax中存放数组
    * array中的下标。
    * 假设遍历到array[i],qmax的放入规则为:
    * 1.如果qmax为空,直接把下标i放进qmax,放入过程结束。
    * 2.如果qmax不为空,取出当前qmax队尾存放的下标,假设为j。
    * 1.如果array[j]>array[i],直接把下标i放到qmax的队尾,放入过程结束。
    * 2.如果array[j]<=array[i],把j从qmax中弹出,重复qmax的放入规则。
    * 实例:
    * 下标: 0 1 2 3 4 5 6 7
    * 大小: 4 3 5 4 3 3 6 7
    *
    *1.开始时qmax为空,即qmax={}。
    *2.遍历到array[0]=4时:
    *由于qmax为空,则将下标0放入到qmax内,此时qmax={0}。
    *3.遍历到array[1]=3时:
    *由于qmax的尾端下标为0,由array[0]>array[1],则将下标1放入到qmax中,此时qmax={0,1}。
    *4.遍历到array[2]=5时:
    *此时窗口array[0,1,2]出现。由于qmax的末尾下标为1,根据array[1]<array[2],故将下标1从qmax末尾弹出,此时qmax={0}。
    *又有array[0]<array[2],故将下标0从qmax末尾弹出,此时qmax={}。
    *由于qmax为空,则将下标2放入到qmax中,此时qmax={2}。
    *由于窗口为[0,1,2],此时下标2还没有过期,故窗口[0,1,2]的最大值是下标2所对应的array[2]。
    *5.遍历到array[3]=4时:
    *此时窗口[1,2,3]出现,由于qmax的末尾下标为2,根据array[2]>array[3],故将下标3放入到qmax中,此时qmax={2,3}。
    *由于窗口为[1,2,3],此时下标2还没有过期,故窗口[1,2,3]的最大值是下标2所对应的array[2]。
    *6.遍历到array[4]=3时:
    *此时窗口[2,3,4]出现,由于qmax的末尾下标为3,根据array[3]>array[4],故将下标4放入到qmax中,此时qmax={2,3,4}。
    *由于窗口为[2,3,4],此时下标2还没有过期,故窗口[2,3,4]的最大值是下标2所对应的array[2]。
    *7.遍历到array[5]=3时:
    *此时窗口[3,4,5]出现,由于qmax的末尾下标为4,根据array[4]=array[5],故将下标4弹出,此时qmax={2,3}。
    *由于此时qmax的末尾下标为3,且array[3]>array[5],故将下标5放入到qmax中,此时下标为qmax={2,3,5}。
    *由于窗口为[3,4,5],此时下标2已经过期,所以将下标2从qmax的头部弹出,此时qmax={3,5}。故窗口[3,4,5]的最大值是下标3所对应的array[3]。
    *8.遍历到array[6]=6时:
    *此时窗口[4,5,6]出现,由于qmax的末尾下标为5,根据array[5]<array[6],故将下标5弹出,此时qmax={3}。
    *由于qmax的末尾下标为3,根据array[3]<array[6],故将下标3弹出,此时qmax={}为空。
    *由于qmax为空,则将下标6存入qmax中,此时qmax={6}。
    *由于窗口为[4,5,6],此时下标6还没有过期,故窗口[4,5,6]的最大值是下标6所对应的array[6]。
    *9.遍历到array[7]=7时:
    *此时窗口[5,6,7]出现,由于qmax的末尾下标为6,根据array[6]<array[7],故将下标6弹出,此时qmax={},为空。
    *由于qmax为空,则将下标7存入qmax中,此时qmax={7}。
    *由于窗口为[5,6,7],此时下标7还没有过期,故窗口[5,6,7]的最大值是下标7所对应的array[7]。
    *
    *上述过程中,每个下标最多进入qmax一次,出qmax一次,所以遍历过程中进出双端队列的时间复杂度是O(n)。
    *
    * @author DELL
    *
    */

    *代码

    import java.util.LinkedList;
    
    public class getMaxArray {
        public int[] getMaxWindow(int array[],int w) {
            
            if(array==null||w<1||array.length<w) {
                throw new RuntimeException("error!your data is not true");
            }
            LinkedList<Integer> qmax = new LinkedList<>();
            //存放的最大值的数组内元素个数最大为n-w+1
            int res[] = new int[array.length-w+1];
            int index = 0;
            for(int i=0;i<array.length;i++) {
                //qmax不为空,且末尾下标对应的数组值小于当前遍历的值,则弹出下标
                //直到qmax为空,或者是末端下标值大则停止遍历将数据追加到双端链表内
                while(!qmax.isEmpty() && array[qmax.peekLast()]<array[i]) {
                    qmax.pollLast();
                }
                qmax.addLast(i);
                //判断下标是否过期
                if(qmax.peekFirst() ==(i-w)) {
                    qmax.pollFirst();
                }
                if(i>= (w-1)) {
                    res[index++] = array[qmax.peekFirst()];
                }
            }
            return res;
        }
        
    import java.util.Random;
    import java.util.Scanner;
    
    public class testGetMaxArray {
        
        public void showArray(int array[]) {
            for(int i:array) {
                System.out.print(i+"	");
            }
        }
        public static void main(String[] args) {
            getMaxArray test = new getMaxArray();
            testGetMaxArray show = new testGetMaxArray();
            Random rand = new Random();
            Scanner sc = new Scanner(System.in);
            
            int N;
            int w;
            System.out.println("请输入数组长度:");
            N=sc.nextInt();
            System.out.println("请输入窗口宽度:");
            w=sc.nextInt();
            
            int array[]= new int[N];
            int res[] = new int[N-w+1];
            for(int i=0;i<N;i++) {
                array[i]=(rand.nextInt(10)+1);
            }
            System.out.println("结果如下");
            show.showArray(array);
            System.out.println();
            res = test.getMaxWindow(array, w);
            show.showArray(res);
        }
    
    }
  • 相关阅读:
    c++爱问的面试问题
    Ognl底层使用
    [勘探开发]成绩,全栈开发,健全&amp;借贷
    FMS4
    Flex远程调用机制RemoteObject应用技巧
    Flex开发框架cairngorm入门实例
    RC1意思
    获取JAVA[WEB]项目相关路径的几种方法
    排序算法
    jQuery Validate
  • 原文地址:https://www.cnblogs.com/walxt/p/12442484.html
Copyright © 2020-2023  润新知