精品推荐:
《征服数据结构》专栏:50多种数据结构彻底征服
《经典图论算法》专栏:50多种经典图论算法全部掌握
最近在网上看到一个帖子,4位阿里P7,35岁被裁后在杭州开了一家很有特点的包子铺,从位置,装修,产品到营销策划都精心设计,用互联网思维降维竞争普通包子铺,结果每月稳赔5万!
--------------下面是今天的算法题--------------
来看下今天的算法题,这题是LeetCode的第239题:滑动窗口最大值。
问题描述
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值 。
输入: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
输入:nums = [1], k = 1
输出:[1]
1 <= nums.length <= 10^5
-10^4 <= nums[i] <= 10^4
1 <= k <= nums.length
问题分析
public int[] maxSlidingWindow(int[] nums, int k) {
int index = 0, len = nums.length;
int[] ans = new int[len - k + 1];
// 双端队列,存储元素的下标
Deque<Integer> deque = new ArrayDeque<>();
for (int i = 0; i < len; i++) {
// 如果队列中队头元素和当前元素位置相差i-k,相当于队头元素要
// 出窗口了,就把队头元素给移除。
if (!deque.isEmpty() && deque.peekFirst() <= i - k)
deque.pollFirst();
// 在添加一个值之前,前面比他小的都要被移除掉,并且还要保证窗口
// 中队列头部元素永远是队列中最大的。
while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i])
deque.pollLast();
deque.addLast(i);// 当前元素的下标加入到队列的尾部。
// 当窗口的长度大于等于k个的时候才开始计算(注意这里的i是从0开始的)。
if (i >= k - 1)
// 队头元素是队列中最大的,把队列头部的元素加入到数组中。
ans[index++] = nums[deque.peekFirst()];
}
return ans;
}
public:
vector<int> maxSlidingWindow(vector<int> &nums, int k) {
int index = 0, len = nums.size();
vector<int> ans(len - k + 1);
// 双端队列,存储元素的下标
deque<int> d;
for (int i = 0; i < len; i++) {
// 如果队列中队头元素和当前元素位置相差i-k,相当于队头元素要
// 出窗口了,就把队头元素给移除。
if (!d.empty() && d.front() <= i - k)
d.pop_front();
// 在添加一个值之前,前面比他小的都要被移除掉,并且还要保证窗口
// 中队列头部元素永远是队列中最大的。
while (!d.empty() && nums[d.back()] < nums[i])
d.pop_back();
d.push_back(i);// 当前元素的下标加入到队列的尾部。
// 当窗口的长度大于等于k个的时候才开始计算(注意这里的i是从0开始的)。
if (i >= k - 1)
// 队头元素是队列中最大的,把队列头部的元素加入到数组中。
ans[index++] = nums[d.front()];
}
return ans;
}
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
index, length = 0, len(nums)
ans = [0] * (length - k + 1)
# 双端队列,存储元素的下标
q = deque()
for i in range(length):
# 如果队列中队头元素和当前元素位置相差i-k,相当于队头元素要
# 出窗口了,就把队头元素给移除。
if q and q[0] <= i - k:
q.popleft()
# 在添加一个值之前,前面比他小的都要被移除掉,并且还要保证窗口
# 中队列头部元素永远是队列中最大的。
while q and nums[q[-1]] < nums[i]:
q.pop()
q.append(i) # 当前元素的下标加入到队列的尾部。
# 当窗口的长度大于等于k个的时候才开始计算(注意这里的i是从0开始的)。
if i >= k - 1:
# 队头元素是队列中最大的,把队列头部的元素加入到数组中。
ans[index] = nums[q[0]]
index += 1
return ans
数组,稀疏表(Sparse Table),单向链表,双向链表,块状链表,跳表,队列和循环队列,双端队列,单调队列,栈,单调栈,双端栈,散列表,堆,字典树(Trie树),ArrayMap,SparseArray,二叉树,二叉搜索树(BST),笛卡尔树,AVL树,树堆(Treap),FHQ-Treap,哈夫曼树,滚动数组,差分数组,LRU缓存,LFU缓存
……
图的介绍,图的表示方式,邻接矩阵转换,广度优先搜索(BFS),深度优先搜索(DFS),A*搜索算法,迭代深化深度优先搜索(IDDFS),IDA*算法,双向广度优先搜索,迪杰斯特拉算法(Dijkstra),贝尔曼-福特算法(Bellman-Ford),SPFA算法,弗洛伊德算法(Floyd),卡恩(Kahn)算法,基于DFS的拓扑排序,约翰逊算法(Johnson)
……