#数据结构与算法学习笔记#剑指Offer62:滑动窗口的最大值 + 在线处理(Java、C/C++)

2019.3.3     《剑指Offer》从零单刷个人笔记整理(66题全)目录传送门​​​​​​​

这道题也是一道效率题,字符串和数组一般可以考虑在线处理。下面对算法过程进行说明:

1.创建一个用于记录元素下标的双端队列list和最终结果序列result。

以下对于测试用例:输入数组{2,3,4,2,6,2,5,1}、滑动窗口大小3,进行算法过程说明。

2.对list进行初始化,从初始窗口倒数第二个元素k开始执行一次操作:从前往后将队列中元素k小的所有元素删除,并将元素k的位置加在队首(记住这次操作,接下来还会用到)。

初始窗口中的元素为{2,3,4},对k=3之前的所有元素进行操作,由于3最大,对应下标为1,最终list={1}。

3.从第一个窗口(第一个窗口最后一个元素)开始,执行上述操作。

第一个窗口中的元素为{2,3,4},对k=4之前的所有元素进行操作,由于4最大,对应下标为1,最终list={2}。

4.对list队尾的最大元素,检查是否超出窗口范围(队首-队尾+1?窗口大小,只需检查一次),若超出则删去队尾元素。将最大元素加入result。

当窗口进行到{3,4,2}的时候,list中的元素为{3,2}(队首为3,队尾最大为2),检查一下3-2+1<3,符合要求,将位置2对应元素4加入result。

当窗口进行到{2,5,1}的时候,list中的元素为{7,6,4}(队首为7,由于6(对应数字5)不比7(对应数字1)小,因此不删除,队尾最大为4(对应数字6)),检查一下队尾7-4+1>3,说明数字6在窗口范围外,删去。list最终为{7,6},将位置6对应元素5加入result。

5.循环上述操作3与检查4的过程,可以保证每次list队尾元素最大。


题目描述

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。


Java实现:

/**
 * 
 * @author ChopinXBP
 * 给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。
 * 例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5};
 * 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: 
 * {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, 
 * {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
 * 
 */

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

public class maxInWindows_63 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] num = {2,3,4,2,6,2,5,1};
		ArrayList result = maxInWindows(num, 3);
		for(int i = 0; i < result.size(); i++) {
			System.out.print(result.get(i) + " ");
		}
	}

    public static ArrayList maxInWindows(int [] num, int size)
    {
    	ArrayList result = new ArrayList<>();
    	if(num == null || size <= 0 || size > num.length) return result;
    	//记录元素下标的队列 (只记录下标)	
    	LinkedList list = new LinkedList<>();
    	//构建初始队列,从初始窗口倒数第二个元素k开始执行一次操作:从前往后将队列中元素k小的所有元素删除,并将元素k加在队首,此时队尾元素最大
    	for(int i = 0; i < size - 1; i++) {
    		while(!list.isEmpty() && num[i] > num[list.peekFirst()]) {
    			list.pollFirst();
    		}
    		list.addFirst(i);
    	}
    	
    	//初始队列最大元素为size - 1个,对与每一个新元素k = num[i]    	
    	for(int i = size - 1; i < num.length; i++) {
    		//从前往后移去比k小的元素,将k插入队首
    		while(!list.isEmpty() && num[i] > num[list.peekFirst()]) {
    			list.pollFirst();
    		}
    		list.addFirst(i);
    		//检查队尾元素(当前最大值的坐标)是否超出窗口范围(被移出窗口),若超出则删去(每次移动最多删去一个)
    		if(i - list.peekLast() + 1 > size) {
    			list.pollLast();
    		}
    		result.add(num[list.peekLast()]);
    	}
    	  	
    	return result;
    }	
}

C++实现示例:

class Solution {
public:
    vector maxInWindows(const vector& num, unsigned int size)
    {
        vector res;
        deque s;
        for(unsigned int i=0;isize)
                s.pop_front();

            //把每次滑动的num下标加入队列
            s.push_back(i);

            //当滑动窗口首地址i大于等于size时才开始写入窗口最大值
            if(size&&i+1>=size)
                res.push_back(num[s.front()]);
        }
        return res;
    }
};

#Coding一小时,Copying一秒钟。留个言点个赞呗,谢谢你#

你可能感兴趣的:(C/C++,数据结构与算法,剑指Offer,JAVA)