剑指offer 面试题65 滑动窗口的最大值

面试题65 滑动窗口的最大值

题目:

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

package foroffer.top70;

import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;

/**
 * description:
 *
 * @author liyazhou
 * @create 2017-06-19 20:53 // 2017-8-21 10:46:30
 *
 * 面试题65:滑动窗口的最大值
 *
 * 题目:
 *      给定一个数组和滑动窗口的大小,请找出所有滑动窗口里的最大值。
 *      例如,如果输入数组 {2, 3, 4, 2, 6, 2, 5, 1}及滑动窗口的大小 3,
 *      那么移动存在 6 个滑动窗口,它们的最大值分别为 {4, 4, 6, 6, 6, 5}。
 *
 * 考查点:
 *      1. 双端队列的应用
 *
 * 思路:
 *      1. 新的元素比队列中的任何元素都大,则清空队列,并将其添加到队尾
 *      2. 新的元素比队尾中的元素小,则将其添加到队尾
 *      3. 新的元素比队尾元素大,但是比队首元素小,则将比其小的元素移出队列,然后将其添加到队尾。(从队尾删除元素)
 *
 *      怎么控制窗口的大小呢?
 *          队列里面存放的是下标,
 *          插入元素之前,先判断尾首下标之差是否等于 n-1,如果是,则将队首元素移出队列
 *
 *
 * Deque的12种方法总结如下:
 *                     First Element (Head)                       Last Element (Tail)
 *              Throws exception    Special value           Throws exception    Special value
 *  Insert        addFirst(e)        offerFirst(e)              addLast(e)       offerLast(e)
 *  Remove        removeFirst()      pollFirst()                removeLast()     pollLast()
 *  Examine       getFirst()         peekFirst()                getLast()        peekLast()
 *
 */
public class Test65 {

    public ArrayList<Integer> maxInWindows(int[] num, int size) {
        ArrayList<Integer> result = new ArrayList<>();
        if (num == null || num.length == 0 || size < 1) return result;

        Deque<Integer> deque = new LinkedList<>();
        for (int i = 0; i < num.length; i ++){
            // 保证添加新的元素之前,窗口中首尾元素下标之差最大是size
            if (i > 0 && !deque.isEmpty()){
                int firstIdx = deque.peekFirst();
                int diff = i - firstIdx;
                if (diff == size)
                    deque.pollFirst();
            }
            /*
            if (!deque.isEmpty() && num[i] > deque.peekFirst()){
                deque.clear();
            }else{
                while(!deque.isEmpty() && num[i] >= deque.peekLast())
                    deque.pollLast();
            }
            */

            // 同一个窗口中的元素如果小于新元素,则被删除
            // 由于前面的元素总是大于后面的元素,所以从后面开始删除
            while(!deque.isEmpty() && num[i] >= num[deque.peekLast()])
                deque.pollLast();

            // 新元素总是会被添加到双端队列的末尾
            deque.offerLast(i);

            // 双端队列的队头存放的是一个窗口的最大值
            if (i >= size-1)
                result.add(num[deque.peekFirst()]);
        }
        return result;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值