【二叉树】【单调双向队列】LeetCode239:滑动窗口最大值

作者推荐

map|动态规划|单调栈|LeetCode975:奇偶跳

涉及知识点

单调双向队列 二叉树

题目

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值 。

示例 1:

输入:nums = 1,3,-1,-3,5,3,6,7, k = 3

输出:3,3,5,5,6,7

解释:

滑动窗口的位置 最大值


1 3 -1 -3 5 3 6 7 3

1 3 -1 -3 5 3 6 7 3

1 3 -1 -3 5 3 6 7 5

1 3 -1 -3 5 3 6 7 5

1 3 -1 -3 5 3 6 7 6

1 3 -1 -3 5 3 6 7 7

示例 2:

输入:nums = 1, k = 1

输出:1
参数范围

1 <= nums.length <= 105

-104 <= numsi <= 104

1 <= k <= nums.length

单调栈

时间复杂度 😮(n)。

queMax中记录(i-k,i],如果i1 < i2,且numsi1 <=numsi2,那么i1无论如何都无法成为最大值。故可以淘汰i1,淘汰i1后,成降序排列。队首元素最大。

对queMax有三种操作。

操作一 队尾淘汰i1
操作二 队尾插入i2
操作三 队首删除i-k,由于操作二,queMax不会为空,所以无需判断是否为空。如果i-k已经被操作一淘汰,则不能删除。

代码

核心代码

cpp 复制代码
class Solution {
public:
	vector<int> maxSlidingWindow(vector<int>& nums, int k) {
		int i = 0;
		std::deque<int> queMax;
		vector<int> vRet;
		for ( i = 0; i < k; i++)
		{
			while (queMax.size() && (nums[queMax.back()] <= nums[i]))
			{
				queMax.pop_back();
			}
			queMax.emplace_back(i);			
		}
		vRet.emplace_back(nums[queMax.front()]);
		for (; i < nums.size(); i++)
		{
			if (i - k == queMax.front())
			{
				queMax.pop_front();
			}
			while (queMax.size() && (nums[queMax.back()] <= nums[i]))
			{
				queMax.pop_back();
			}
			queMax.emplace_back(i);
			vRet.emplace_back(nums[queMax.front()]);
		}
		return vRet;
	}
};

测试用例

cpp 复制代码
template<class T>
void Assert(const T& t1, const T& t2)
{
	assert(t1 == t2);
}

template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() != v2.size())
	{
		assert(false);
		return;
	}
	for (int i = 0; i < v1.size(); i++)
	{
		Assert(v1[i], v2[i]);
	}
}


int main()
{
	vector<int> nums;
	int k;
	{
		Solution sln;
		nums = { 1, 3, -1, -3, 5, 3, 6, 7 }, k = 3;
		auto res = sln.maxSlidingWindow(nums, k);
		Assert(vector<int>{ 3,3,5,5,6,7 }, res);
	}
	{
		Solution sln;
		nums = { 1 }, k = 1;
		auto res = sln.maxSlidingWindow(nums, k);
		Assert(vector<int>{ 1 }, res);
	}

//CConsole::Out(res);
}

2023年3月二叉树

用多键二叉树(红黑树)mulset记录滑动窗口中的数,由于二叉树默认是升序排列,所以最后一个元素,就是最大值。由于二叉树的插入、删除的时间复杂度是O(logn),故总时间复杂度是O(nlogn)

cpp 复制代码
 class Solution {
 public:
	 vector<int> maxSlidingWindow(vector<int>& nums, int k) {
		 int i = 0;
		 std::multiset<int> setNums;
		 for (; i + 1 < k; i++)
		 {
			 setNums.insert(nums[i]);
		 }
		 vector<int> vRet;
		 for (; i < nums.size(); i++)
		 {
			 setNums.insert(nums[i]);
			 vRet.push_back(*setNums.rbegin());
			 auto it = setNums.find(nums[i + 1 - k]);
			 setNums.erase(it);
		 }
		 return vRet;
	 }
 };

2023年3月第二版

class Solution {

public:

vector maxSlidingWindow(vector& nums, int k) {

vector<pair<int, int>> vValueIndex;

vector vRet;

int iPos = 0;

for (int i = 0; i < nums.size(); i++)

{

while ( ( vValueIndex.size() > iPos ) && (numsi >= vValueIndex.back().first))

{

vValueIndex.pop_back();

}

vValueIndex.emplace_back(numsi, i);

if (i + 1 >= k)

{

vRet.push_back(vValueIndexiPos.first);

}

if (i + 1 - k == vValueIndexiPos.second)

{

iPos++;

}

}

return vRet;

}

};

2023年8月版

class Solution{

public:

vector maxSlidingWindow(vector&nums, int k) {

m_c = nums.size();

//每k个元素用一组,vLeft各元素到组首的最大值,vRight各元素到组尾的最大值

vector vLeft(m_c), vRight(m_c);

int iMax = 0;

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

{

if (0 == i % k)

{

iMax = numsi;

}

else

{

iMax = max(iMax, numsi);

}

vLefti = iMax;

}

iMax = -100 * 1000;

for (int i = m_c-1;i >= 0 ; i-- )

{

if (0 == (i+1) % k)

{

iMax = numsi;

}

else

{

iMax = max(iMax, numsi);

}

vRighti = iMax;

}

vector vRet;

for (int i = k-1; i < m_c; i++)

{

vRet.emplace_back( max(vRighti-k+1, vLefti));

}

return vRet;

}

int m_c;

};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关

下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境: VS2022 C++17

如无特殊说明,本算法C++ 实现。

相关推荐
_wyt0018 小时前
洛谷 B3930 [GESP202312 五级] 烹饪问题 题解
c++·gesp
通信小呆呆10 小时前
当算法有了“五感”:多模态数据融合如何向人体感官协同学习?
人工智能·学习·算法·机器学习·机器人
benben04411 小时前
强化学习之DQN算法族(基于gymnasium开发)
算法
小小工匠11 小时前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
玖玥拾12 小时前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
何以解忧,唯有..12 小时前
Go语言循环语句详解:for、range与循环控制
开发语言·算法·golang
想吃火锅100512 小时前
【leetcode】88.合并两个有序数组js
算法
один but you13 小时前
constexpr函数
c++
生成论实验室13 小时前
机器人:一个自主运动的系统
人工智能·算法·语言模型·机器人·自动驾驶·agi·安全架构