面试题59:队列的最大值

题目:

滑动窗口的最大值

给定一个数字和滑动窗口的大小,请找出所有滑动窗口中的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,它们的最大值分别是{4,4,6,6,6,5}。

分析:

以数组{2,3,4,2,6,2,5,1}和滑动窗口的大小3为例分析。这里用一个双端队列辅助分析问题。从前到后遍历数组。

第一个数字2,当前值的下标入队列。

第二个数字3,大于队列中的数字2,也就是3入队列后,2不可能是滑动窗口中的最大元素,将2移出,当前值的下标入队列。

第三个数字4,大于队列中的数字3,也就是4入队列后,3不可能是滑动窗口中的最大元素,将3移出,当前值的下标入队列。

第四个数字2,当滑动窗口把最左端元素4滑出时,2可能成为滑动窗口中的最大值,当前值的下标入队列。

第五个数字6,6的到来,让队列中的4和2不可能成为滑动窗口中的最大值,将4,2依次出队列,当前值的下标入队列。

第六个数字2,当滑动窗口把最左端元素6滑出时,2可能成为滑动窗口中的最大值,当前值的下标入队列。

第七个数字5,5的到来,2不可能成为滑动窗口中的最大值,于是2出队列,当滑动窗口把最左端元素6滑出时,5可能成为滑动窗口的最大值,当前值的下标入队列。

第八个数字1,当滑动窗口把最左端的6,5滑出时,1可能成为滑动窗口中的最大值,当前值的下标入队列。

对于上面的每个数字,都面临下面几种情况:

  1. 根据当前值和队列中下标对应的值的大小关系,确定是否从队列尾删除元素。
  2. 根据当前坐标i-size+1,判断是否删除队列头的元素。当i-size+1>对头的下标时,对头元素也要出队,因为滑动窗口最左端已经超出了这个索引。
  3. 当前元素索引入队列。
  4. 滑动窗口里包含的元素达到size的时候,开始统计滑动窗口中的最大值,当i-size+1≥0的时候,开始统计滑动窗口中的最大值。

解法:

package com.wsy;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        int[] array = new int[]{2, 3, 4, 2, 6, 2, 5, 1};
        int size = 3;
        int length = array.length;
        LinkedList<Integer> linkedList = new LinkedList<Integer>();
        List<Integer> result = new ArrayList<Integer>();
        for (int i = 0; i < length; i++) {
            if (linkedList.isEmpty()) {
                linkedList.add(i);
            } else {
                while (!linkedList.isEmpty() && array[i] > array[linkedList.getLast()]) {
                    linkedList.removeLast();
                }
                linkedList.add(i);
                if (i - size + 1 > linkedList.peek()) {// 当前索引i - size + 1 的值比队列首的索引大,此时滑动窗口左侧就超出了队首的下标值
                    linkedList.removeFirst();
                }
            }
            if (i - size + 1 >= 0) {// 滑动窗口中包含size个元素,此时获取滑动窗口中的最大值,也就是linkedList的首元素
                result.add(array[linkedList.peek()]);
            }
        }
        System.out.println(result);
    }
}

题目:

队列的最大值

请定义一个队列,并实现函数max得到队列里的最大值,要求函数max、push_back和pop_front的时间复杂度都是O(1)。

分析:

同样用一个双端队列辅助完成这个功能,不过,此时不需要检查滑动窗口的左侧了,只有在pop_front的时候,才需要移出左侧元素,其他时候,都是push_back()操作,在push之前,需要让队列中小于当前值的元素先出来,再push进去。

解法:

package com.wsy;

import java.util.LinkedList;

class InternalData {
    private int number;
    private int index;

    public InternalData() {
    }

    public InternalData(int number, int index) {
        this.number = number;
        this.index = index;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }
}

public class Main {
    public static int index;
    public static LinkedList<InternalData> data;
    public static LinkedList<InternalData> maximum;

    public static void main(String[] args) {
        index = 0;
        data = new LinkedList<InternalData>();
        maximum = new LinkedList<InternalData>();
        push_back(2);// {2}
        System.out.println(max() == 2);
        push_back(3);// {2,3}
        System.out.println(max() == 3);
        push_back(1);// {2,3,1}
        System.out.println(max() == 3);
        pop_front();// {3,1}
        System.out.println(max() == 3);
        pop_front();// {1}
        System.out.println(max() == 1);
    }

    public static void push_back(int number) {
        InternalData internalData = new InternalData(number, index++);
        data.add(internalData);
        while (!maximum.isEmpty() && maximum.getLast().getNumber() < number) {
            maximum.removeLast();
        }
        maximum.add(internalData);
    }

    public static void pop_front() {
        if (data.isEmpty()) {
            System.out.println("队列为空,无法删除");
            return;
        }
        InternalData internalData = data.removeFirst();
        if (internalData.getIndex() == maximum.getFirst().getIndex()) {
            maximum.removeFirst();
        }
    }

    public static int max() {
        if (maximum.isEmpty()) {
            System.out.println("队列为空,没有最大值");
            return 0;
        }
        return maximum.getFirst().getNumber();
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值