滑动窗口最大值 java_滑动窗口的最大值

129

推荐

import java.uti

查看全部

编辑于 2015-09-02 14:11:26

回复(50)

157

//引用马客(Mark)的解题思路,马客没加注释,我用自己的理解加下注释,希望对你们有用,

//如有错误,见谅,我会及时修改。

//deque s中存储的是num的下标

class Solution {

public:

vector maxInWindows(const vector& num, unsigned int size)

{

vector res;

deque s;

for(unsigned int i=0;i

while(s.size() && num[s.back()]<=num[i])//从后面依次弹出队列中比当前num值小的元素,同时也能保证队列首元素为当前窗口最大值下标

s.pop_back();

while(s.size() && i-s.front()+1>size)//当当前窗口移出队首元素所在的位置,即队首元素坐标对应的num不在窗口中,需要弹出

s.pop_front();

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

if(size&&i+1>=size)//当滑动窗口首地址i大于等于size时才开始写入窗口最大值

res.push_back(num[s.front()]);

}

return res;

}

};

编辑于 2016-06-27 16:21:02

回复(33)

69

/**

* 题目:滑动窗口的最大值

* 思路:滑动窗口应当是队列,但为了得到滑动窗口的最大值,队列序可以从两端删除元素,因此使用双端队列。

* 原则:

* 对新来的元素k,将其与双端队列中的元素相比较

* 1)前面比k小的,直接移出队列(因为不再可能成为后面滑动窗口的最大值了!),

* 2)前面比k大的X,比较两者下标,判断X是否已不在窗口之内,不在了,直接移出队列

* 队列的第一个元素是滑动窗口中的最大值

*/

public class P65_滑动窗口的最大值 {

public ArrayList maxInWindows(int [] num, int size)

{

ArrayList ret = new ArrayList<>();

if (num == null) {

return ret;

}

if (num.length < size || size < 1) {

return ret;

}

LinkedList indexDeque = new LinkedList<>();

for (int i = 0; i < size - 1; i++) {

while (!indexDeque.isEmpty() && num[i] > num[indexDeque.getLast()]) {

indexDeque.removeLast();

}

indexDeque.addLast(i);

}

for (int i = size - 1; i < num.length; i++) {

while (!indexDeque.isEmpty() && num[i] > num[indexDeque.getLast()]) {

indexDeque.removeLast();

}

indexDeque.addLast(i);

if (i - indexDeque.getFirst() + 1 > size) {

indexDeque.removeFirst();

}

ret.add(num[indexDeque.getFirst()]);

}

return ret;

}

}

编辑于 2016-04-10 23:18:06

回复(12)

43

import java.util.*;

public class Solution {

public ArrayList maxInWindows(int [] num, int size) {

if (num == null || num.length == 0 || size <= 0 || num.length < size) {

return new ArrayList();

}

ArrayList result = new ArrayList<>();

//双端队列,用来记录每个窗口的最大值下标

LinkedList qmax = new LinkedList<>();

int index = 0;

for (int i = 0; i < num.length; i++) {

while (!qmax.isEmpty() && num[qmax.peekLast()] < num[i]) {

qmax.pollLast();

}

qmax.addLast(i);

//判断队首元素是否过期

if (qmax.peekFirst() == i - size) {

qmax.pollFirst();

}

//向result列表中加入元素

if (i >= size - 1) {

result.add(num[qmax.peekFirst()]);

}

}

return result;

}

}

发表于 2018-03-10 21:55:47

回复(14)

27

import java.util.*;

public class Solution {

public ArrayList maxInWindows(int [] num, int size){

ArrayList list = new ArrayList ();

if(size>num.length||size==0)

return list;

for(int i = 0;i<=num.length-size;i++){

int max = num[i];

for(int j = i+1;j

if(num[j]>max){

max = num[j];

}

}

list.add(max);

}

return list;

}

}

发表于 2016-04-18 13:45:11

回复(13)

51

//单调队列,O(n)

class Solution {

public:

vector maxInWindows(const vector& a, unsigned int k){

vector res;

deque s;

for(unsigned int i = 0; i < a.size(); ++i){

while(s.size() && a[s.back()] <= a[i]) s.pop_back();

while(s.size() && i - s.front() + 1 > k) s.pop_front();

s.push_back(i);

if(k && i + 1 >= k) res.push_back(a[s.front()]);

}

return res;

}

};

编辑于 2015-09-17 14:02:16

回复(7)

29

Python solution

1. 利用python性质每次求固定size的最大值,时间复杂度O(n*size) res, i = [], 0

while size > 0 and i + size - 1 < len(num):

res.append(max(num[i:i + size]))

i += 1

return res

2. 双向队列,queue存入num的位置,时间复杂度O(n) queue,res,i = [],[],0

while size>0 and i

if len(queue)>0 and i-size+1 > queue[0]: #若最大值queue[0]位置过期 则弹出

queue.pop(0)

while len(queue)>0 and num[queue[-1]]

queue.pop()

queue.append(i)

if i>=size-1:

res.append(num[queue[0]])

i += 1

return res

发表于 2018-10-24 22:07:14

回复(5)

23

class Solution {

public:

//时间复杂度o(n),空间复杂度为o(n)

/*思路就是采用双端队列,队列中的头节点保存的数据比后面的要大。

比如当前假如的数据比队尾的数字大,说明当前这个数字最起码在从现在起到后面的过程中可能是最大值

,而之前队尾的数字不可能最大了,所以要删除队尾元素。

此外,还要判断队头的元素是否超过size长度,由于存储的是下标,所以可以计算得到;

特别说明,我们在双端队列中保存的数字是传入的向量的下标;

*/

vector maxInWindows(const vector& num, unsigned int size)

{

vector vec;

if(num.size()<=0 || num.size()

deque dq;

//处理前size个数据,因为这个时候不需要输出最大值;

for(unsigned int i=0;i

{

//假如当前的元素比队列队尾的元素大,说明之前加入的这些元素不可能是最大值了。因为当前的这个数字比之前加入队列的更晚

while(!dq.empty()&&num[i]>=num[dq.back()])

dq.pop_back();//弹出比当前小的元素下标

dq.push_back(i);//队尾压入当前下标

}

//处理size往后的元素,这时候需要输出滑动窗口的最大值

for(unsigned int i=size;i

{

vec.push_back(num[dq.front()]);

while(!dq.empty()&&num[i]>=num[dq.back()])

dq.pop_back();

if(!dq.empty() && dq.front()<=(int)(i-size))//判断队头的下标是否超出size大小,如果超过,要删除队头元素

dq.pop_front();//删除队头元素

dq.push_back(i);//将当前下标压入队尾,因为可能在未来是最大值

}

vec.push_back(num[dq.front()]);//最后还要压入一次

return vec;

}

};

发表于 2016-07-29 14:41:00

回复(5)

12

我看见都用了队列,就想了一个不用队列的方法,虽然有点麻烦。。。

首先,用一个值index记录窗口最大值的位置,以及一个记录窗口最大值的max。

然后就可以用i遍历数组了,用index和i比较,小于就说明窗口最左边已经过了之前的那个最大值,于是从i向右size个单位找到最大值,并记录,不小于就说明最大值还在窗口内,由于窗口每次滑动都会向右移动一个元素,使用这个元素和max比较再记录。最后添加到ArrayList中。 import java.util.*;

public class Solution {

public ArrayList maxInWindows(int [] num, int size)

{

ArrayList list = new ArrayList<>();

if (num == null) {

return list;

}

if (num.length < size || size < 1) {

return list;

}

int max = 0;//记录每个窗口的最大值

int index = -1;//这个是记录这个窗口的最大值的位置

for(int i = 0; i <= num.length - size; i++){

if(index < i){//当最大位置的索引小于i的时候,就说明窗口过了这个元素

max = num[i];

for(int j = i; j < i + size; j++){//那么就从这个元素开始向后查找这个窗口的最大值

if(max <= num[j]){

index = j;

max = num[j];

}

}

} else{//没过的话,就判断这个窗口的最后一个元素是否比max大。

if(max <= num[i + size - 1]){

index = i + size - 1;

max = num[i + size - 1];

}

}

list.add(max);

}

return list;

}

}

发表于 2018-05-10 10:56:54

回复(6)

11

class Solution {

public:

//最大堆实现,复杂度O(nlogn)

typedef pair Pair;

vector maxInWindows(const vector &num,

unsigned int size) {

vector result;

priority_queue Q;

if (num.size() < size || size < 1)

return result;

for (int i = 0; i < size-1; i++)

Q.push(Pair(num[i],i));

for (int i = size-1; i < num.size(); i++) {

Q.push(Pair(num[i],i));

Pair p = Q.top();

while(p.second < i-(size-1)) {

Q.pop();

p = Q.top();

}

result.push_back(p.first);

}

//        result.push_back(Q.top().first);

return result;

}

// 双向队列实现,复杂度O(n)

vector maxInWindows(const vector &num,

unsigned int size) {

vector result;

deque Q;

//        int n = num.size();

if(num.size()

return result;

for (int i = 0; i < size; i++) {

while (!Q.empty() && num[i] > num[Q.back()]) Q.pop_back();

Q.push_back(i);

}

for (int i = size; i < num.size(); i++) {

result.push_back(num[Q.front()]);

while (!Q.empty() && num[i] >= num[Q.back()]) Q.pop_back();

while (!Q.empty() && Q.front() <= i - size) Q.pop_front();

Q.push_back(i);

}

result.push_back(num[Q.front()]);

return result;

}

};

编辑于 2015-05-06 23:13:38

回复(4)

9

被无符号整形坑了。。。

unsigned int v=1;

unsigned int b=5;

cout<

i-q_max.front()+1>size(判断是否要把队列第一个给pop出去,当它已经在窗口外时)

所以这个要这么写

之前写成

q_max.front()

逻辑上是一样的,但是需要负数存在,开始还没想明白

发表于 2017-05-05 20:12:13

回复(3)

11

package StackAndQueue;

import java.util.ArrayList;

import java.util.Deque;

import java.util.LinkedList;

import java.util.PriorityQueue;

/**

* 滑动窗口的最大值

* 给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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]}。

*/

public class Solution52 {

public static void main(String[] args) {

Solution52 solution52 = new Solution52();

int[] num = {2, 3, 4, 2, 6, 2, 5, 1};

int size = 3;

ArrayList list = solution52.maxInWindows(num, size);

System.out.println(list);

}

/**

* 最大堆方法

* 构建一个窗口size大小的最大堆,每次从堆中取出窗口的最大值,随着窗口往右滑动,需要将堆中不属于窗口的堆顶元素删除。

*

* [@param num

* @param size

* @return](/profile/547241) */

public ArrayList maxInWindows_2(int[] num, int size) {

ArrayList res = new ArrayList();

if (size > num.length || size < 1) return res;

// 构建最大堆,即堆顶元素是堆的最大值。

PriorityQueue heap = new PriorityQueue((o1, o2) -> o2 - o1);

for (int i = 0; i < size; i++) heap.add(num[i]);

res.add(heap.peek());

for (int i = 1; i + size - 1 < num.length; i++) {

heap.remove(num[i - 1]);

heap.add(num[i + size - 1]);

res.add(heap.peek());

}

return res;

}

/**

* 双队列方法

* 滑动窗口的最大值总是保存在队列首部,队列里面的数据总是从大到小排列。

*

* [@param num

* @param size

* @return](/profile/547241) */

public ArrayList maxInWindows(int[] num, int size) {

ArrayList res = new ArrayList();

if (num == null || num.length == 0 || size == 0 || size > num.length) {

return res;

}

Deque deque = new LinkedList();

for (int i = 0; i < num.length; i++) {

if (!deque.isEmpty()) {

// 如果队列头元素不在滑动窗口中了,就删除头元素

if (i >= deque.peek() + size) {

deque.pop();

}

// 如果当前数字大于队列尾,则删除队列尾,直到当前数字小于等于队列尾,或者队列空

while (!deque.isEmpty() && num[i] >= num[deque.getLast()]) {

deque.removeLast();

}

}

deque.offer(i); // 入队列

// 滑动窗口经过一个滑动窗口的大小,就获取当前的最大值,也就是队列的头元素

if (i + 1 >= size) {

res.add(num[deque.peek()]);

}

}

return res;

}

}

编辑于 2018-04-19 12:56:37

回复(4)

6

滑动窗口。

1)判断是否合法输入。

2)合法,则找出0~size-1 中最大值,其坐标为index。

3)滑动,判断index是否过期,过期则找到窗口中的最大值的index。添加到list当中。

import java.util.ArrayList;

public class Solution {

public ArrayList maxInWindows(int [] num, int size)

{

ArrayList list=new ArrayList ();

if(num==null||num.length

//int max=num[0];

int index=0;

index=findMax(num,size,0);

list.add(num[index]);

for(int i=size;i

if(index<=i-size){index=findMax(num,size,index+1);}//判断是否过期,过期则找到最新的最大值

if(num[index]

list.add(num[index]);

}

return list;

}

public int findMax(int [] num,int size,int begin){

//int max=num[begin];

int index=begin;

for(int i= begin+1;i< begin+size;i++){

if(num[index]

{

// max=num[i];

index=i;

}

}

return index;

}

}

发表于 2016-08-30 21:55:40

回复(3)

7

一个i指示每个窗口的起点,在i循环内j遍历该窗口找出最大值。

改进的话,先找出第一个窗口中的最大值,然后窗口移动的时候观察上个窗口的最大值是否移除,如果移除就在新窗口中重新遍历计算,如没有移除就直接比较新加入窗口的数和上个窗口最大值,得出该窗口最大值。

下面是普通的解法:

classSolution {

public:

vector maxInWindows(constvector& num, unsigned intsize)

{

intlen = num.size();

vector result;

if(len < size||size==0)

returnresult;

for(inti=0; i<=len-size; i++)

{

intmax = num[i];

for(intj = i; j< i+size;j++)

{

if(num[j]>max)

max = num[j];

}

result.push_back(max);

}

returnresult;

}

};

编辑于 2015-09-02 15:33:42

回复(2)

4

class Solution {

public:

//只考虑两端增删变化的影响

int MaxinW(const vector& num, int low, int high)

{

int MaxVal = INT_MIN;

for (int j = low; j <= high; j++)

MaxVal = max(num[j], MaxVal);

return MaxVal;

}

vector maxInWindows(const vector& num, unsigned int size)

{

vectorres;

int len=num.size();

if (len len)return res;

int MaxVal = MaxinW(num, 0, size - 1); res.push_back(MaxVal);

for (int low = 1, high = size; high < len; low++,high++)

{

if (num[high] >= MaxVal)

MaxVal = num[high];

if (num[low - 1] == MaxVal)

MaxVal = MaxinW(num, low, high);

res.push_back(MaxVal);

}

return res;

}

};

2.参考牛友 class Solution {

public:

//双端队列

//时间复杂度o(n),空间复杂度为o(n)

//deque s中存储的是num的下标

vector maxInWindows(const vector& num, unsigned int size)

{

vectorres;

deques;

int len=num.size();

if (len <= 0||size<=0||size>len)return res;

for (int i = 0;i < len; i++)

{

while (!s.empty() && num[s.back()] <= num[i])//当前值比队列从后往前的大,成为下一个待选值

s.pop_back();

while (!s.empty()&&i - s.front() + 1>size)//最大值已不在窗口中

s.pop_front();

s.push_back(i);

if (i + 1 >= size)//当滑动窗口首地址i大于等于size时才开始写入窗口最大值

res.push_back(num[s.front()]);

}

return res;

}

};

编辑于 2018-12-10 16:29:50

回复(1)

15

python O(n) solution # -*- coding:utf-8 -*-

class Solution:

def maxInWindows(self, nums, k):

# write code here

if not k or k>len(nums):return []

cur_max = max(nums[:k])

max_nums = [cur_max]

for i in range(0, len(nums) - k):

if nums[i] == cur_max:

cur_max = max(nums[i + 1:i + k + 1])

elif nums[i + k] > cur_max:

cur_max = nums[i + k]

max_nums.append(cur_max)

return max_nums

编辑于 2017-10-14 08:07:13

回复(6)

3

# -*- coding:utf-8 -*-

class Solution:

def maxInWindows(self, num, size):

# write code here

maxInWindows = []

#最主要是考虑当size是0的情况,如果size为0就返回空列表,否则将进行滑动。

if size == 0:

return maxInWindows

#首先确定要滑动多少次,应该是总长-滑动窗口大小。

for i in range(0,len(num)-size+1):

InWindowsNum = num[i:i+size]

max = []

#比较滑动窗口中的最大值

for j in InWindowsNum:

if len(max) == 0:

max.append(j)

else:

if j > max[0]:

max[0] = j

maxInWindows.append(max[0])

return maxInWindows

发表于 2019-12-25 16:11:45

回复(0)

3

双端队列,两端删除添加可用数组模拟。

push/pop操作最后

unshift/shift操作最前 function maxInWindows(num, size)

{

// 双端队列(两端都可以实现插入和删除)

// 队列首位永远是最大值

// 每次进来一个数,依次和前面的数比较,如果进来的数大,则前面的数直接弹出(在后面不可能最大)

// 如果进来的数小,则比较下标,下标不存在的将其删除

// 数组实现双端队列,arr存的是下标,arr[0]存最大值下标

var arr = [];

// 结果数组

var res = [];

if (size === 0) {

return res;

}

for (var i = 0; i < num.length; i++) {

// 从第一个开始循环(可以理解成滑动窗口右侧从第一个移动到最后一个)

// 进来一个数,依次从最后一个数开始比较

while (arr.length > 0 && num[i] > num[arr[arr.length-1]]) {

// 如果进来的数比最后一个大,则将最后一个踢出去,pop

arr.pop();

}

arr.push(i);

// 再判断前面的数是否超了,由于每次进来的数如果更大,则将前面的踢出去,导致arr[0]的下标永远在最前面

if (i - arr[0] + 1 > size) {

arr.shift();

}

if (i >= size - 1) {

res.push(num[arr[0]]);

}

}

return res;

}

var res = maxInWindows([2,3,4,2,6,2,5,1], 3);

console.log(res);

发表于 2019-08-08 21:10:29

回复(0)

2

#python2.7 O(n) 时间24ms 内存5760k

class Solution:

def maxInWindows(self, num, size):

# write code here

length = len(num)

if size<=0 or size>length:return []

i = 0

ans =[max(num[:size])]

while size+i < length:

if num[i]

ans.append(max([ans[-1],num[i+size]]))

else:

ans.append(max(num[i+1:i+size+1]))

i+=1

return ans

发表于 2017-12-08 10:35:35

回复(1)

3

/*

表达不清楚的地方,请各位批评指正!

这道题可以用双向队列解决(就是头尾都可以push,pop的队列)

时间复杂度 O(N)

方法如下几点:

1.当我们遇到新数时候,将新的数和双向队列的末尾比较,

若果末尾比新数小,则把末尾pop_back,

直到末尾比新数大或者队列为空才停止;

2.这样就保证队列元素是从头到尾降序的,

由于队列里只有窗口内的数,所以它们其实是窗口内

第一大,第二大…的数。

3.保持队列里只有窗口大小的数的方法是,

右边进一个,左边出一个。

4.由于队列加新数时,已经删除了部分没用的数,

所以队列头的数并不一定是窗口最左的数,

这里有个小技巧,就是队列中存原数组的下标,

这样既可以得到这个数,也可以判断是否是窗口

左边的数了。

*/

class Solution {

public:

vector maxInWindows(const vector& num, unsigned int size)

{

vector ret;

if(num.empty() || size == 0)

return ret;

deque deq;

for(unsigned int i = 0;i < num.size(); ++i){

//每当新数进来时,如果队列头部的下标是窗口最左边的下标,则删除队列头

if(!deq.empty() && deq.front() < i - size)

deq.pop_front();

//队列中加入新数

deq.push_back(i);

//队列头部就是该窗口最大的!

if((i + 1) >= size)

ret.push_back(num[deq.front()]);

}

return ret;

}

};

编辑于 2016-09-02 21:16:31

回复(3)

2

import java.util.*;

public class Solution {

public ArrayList maxInWindows(int [] num, int size)

{

if(num == null || size == 0 || size > num.length) {

return new ArrayList();

}

int windowNum = num.length - size + 1;

LinkedList list = new LinkedList<>();

ArrayList res = new ArrayList<>();

int maxTmp = Integer.MIN_VALUE;

for(int i = 0; i < windowNum; i++) {

maxTmp = num[i];

for (int j = 1; j < size; j++) {

maxTmp = num[i+j] > maxTmp ? num[i+j] : maxTmp;

}

res.add(maxTmp);

}

return res;

}

}

发表于 2018-08-14 15:37:02

回复(1)

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值