#include <iostream>
#include <deque>
#include <vector>
using namespace std;
vector<int> getMaxValueFixedWindow(vector<int> vecSrcData , int windowSize)
{
//思路分析:
//方案一:从头开始遍历整个vecSrcData,然后写一个工具函数getFixNumsMax(vector<int> vecFixNum, int startIndex, int FixNum),
//求得指定数目的vector中的元素的最大值;然后随着vecSrcData的不断遍历,依次得到从startIndex开始的每windowSize个元素组成的vec
//的最大值放入结果vecResult中,(getFixNumsMax是遍历整个窗口元素取得最值),但是通过这种遍历窗口中的所有元素的方法找出当前窗口
//里面的最大值的复杂度是o(kn)级别,复杂度有点高
//方案二:优化
//首先滑动窗口滑过所有的元素必然要经历o(n)的时间,这没法调整,所以可以优化的方向在于获取当前窗口的最大值,
//即想办法从o()优化到 o(1ogk)或者直接优化到o(1),即想办法用最少的代价得到当前滑动窗口的最值,加快得到最值的处理速度
//最好就是能实时获取到每个窗口的最值,就是窗口动了一下,立马就能得到当前窗口的最值,
//对于这种取得实时一组数据的结果,取得实时进展的类型场景,我们可以利用一下双端队列,队首就是实时的结果,
//队首以后的元素具有是下次实时结果的可能性
//此题目可以维护一个单调递减的双端队列,维护这个双端队列从队首到队尾是单调递减的,队首元素是当前窗口的最大值,他之后的元素可能是下个窗口的最值,
//因为这个队首元素应该随着滑动窗口滑出窗口区域也弹出队列
vector<int> resultVec;
if ((int)vecSrcData.size() < windowSize && (int)vecSrcData.size() > 0 && windowSize > 0) return resultVec;
//用于辅助存储实时阶段的最值和未来有希望成为最值的元素的双端队列
deque<int> helperDeque;
//先让窗口滑动K个位置,并且在滑动K下,并且实时更新helperDeque的数据,从而在helperDeque的队首取得resultVec的第一个值
for (int i = 0; i < windowSize; i++)
{
初步思路,若队列为空,即最初状态,遍历到vecSrcData的第一个元素是,直接将他放入队列
//if (helperDeque.empty())
//{
// helperDeque.push_back(vecSrcData[i]);
//}
//else
//{
// //若是队列不为空,放入的时候要注意维护队列是一个从队首到队尾是一个递减状态的队列,
// while(!helperDeque.empty() && vecSrcData[i] > helperDeque.back())
// {
// helperDeque.pop_back();//弹出的时候需要加入条件!helperDeque.empty()放置崩溃
// }
// //弹出了队列中所有比当前即将加入窗口的元素小的数据
// helperDeque.push_back(vecSrcData[i]);
//}
//上面很恶心:39 49行都有helperDeque.push_back(vecSrcData[i]);直接就能提出来,一旦提出来,就能发现,第一个if没有用了
//优化上面的if else while 的结构逻辑;即队列为空直接擦汗如队列,不空的话,
//弹出所有比进入窗口元素值小的队列的元素,然后将该值放入队列
while (!helperDeque.empty() && vecSrcData[i] > helperDeque.back())
{
helperDeque.pop_back();//弹出的时候需要加入条件!helperDeque.empty()放置崩溃
}
helperDeque.push_back(vecSrcData[i]);
}
resultVec.push_back(helperDeque.front());
//从vec的下标为windowSize的元素开始到i成为vecSrcData的最后一个元素,每移动一下窗口都是满的,都应该在result里填充一个值,
for (int i = windowSize; i < (int)vecSrcData.size(); i++)
{
//这时候要注意,滑动窗口滑动那一下,出了窗口的那个元素如果是队首的元素,队首元素也要弹出队列
if (helperDeque.front() == vecSrcData[i - windowSize])//vecSrcData[i - windowSize]就是刚刚滑出滑动窗口外面的那个元素
{
helperDeque.pop_front();
}
//每个元素的进入滑动窗口的时候,维持队列是一个从队首到队尾是一个递减状态的队列的处理逻辑
while (!helperDeque.empty() && vecSrcData[i] > helperDeque.back())
{
helperDeque.pop_back();//弹出的时候需要加入条件!helperDeque.empty()放置崩溃
}
helperDeque.push_back(vecSrcData[i]);
//每移动一下窗口都是满的,都应该在result里填充一个值,
resultVec.push_back(helperDeque.front());
}
return resultVec;
}
int main()
{
vector<int> vecSrcData = { 1, 3, -1, -3, 5, 3, 6, 7 };
int windowSize = 3;
vector<int> resultVec = getMaxValueFixedWindow(vecSrcData , windowSize);
for (int i = 0; i < (int)resultVec.size(); i++)
{
cout << resultVec[i] << endl;
}
}