剑指 Offer 59 - I. 滑动窗口的最大值
题目

思路
使用队列维护一个窗口中的最大值,分为两个阶段,还未形成窗口时,以及形成窗口时(此时仅是窗口的右移,大小已经固定住);
未形成窗口时:判断当前进来的值与队列尾部的值大小,对于比当前值小的队列中的数字清除
形成窗口时:
1.判断窗口弹出的数字是否为队列中队首(最大值),如果是则将队首删除,不是则无影响
2.重复未形成窗口时的步骤,对新进来的值,将队列由右向左依次比较,队列中比当前值小的数字删除
代码
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums.length==0||k==0) return new int[0];
Deque<Integer> deque=new LinkedList<>();
int[] res=new int[nums.length-k+1];
// 分情况讨论,对于未形成队列时
for(int i=0;i<k;i++){
// 对于队列由后向前遍历,只要队列最后一个数字小于当前的nums[i] 就要将其删除
while(!deque.isEmpty()&&deque.peekLast()<nums[i]) deque.removeLast();
// 执行完上述操作之后,将新的nums[i]加入队列的末尾
deque.addLast(nums[i]);
}
res[0]=deque.peekFirst();
// 已经行成了队列,对于每次窗口的移动,维护一个递减的队列
for(int i=k;i<nums.length;i++){
// 判断输出的nums[i-k]是否为当前队列中最大值,若是
if(deque.peekFirst()==nums[i-k]) deque.removeFirst();
while(!deque.isEmpty()&&deque.peekLast()<nums[i]) deque.removeLast();
deque.addLast(nums[i]);
res[i-k+1]=deque.peekFirst();
}
return res;
}
}
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
if len(nums)==0 or k==0:return []
res=[]
# 使用列表当作队列使用
deque=[]
for i in range(k):
while deque and deque[-1]<nums[i]: deque=deque[:-1]
deque.append(nums[i])
res.append(deque[0])
# 对于已经形成窗口的情况
for i in range(k,len(nums)):
# 判断输出的这个数字是否为为当前队列中的最大值,如果是则将最大值去掉
# 注意!!!当前deque前面比最大值小的数字都没有存在于列表中(所以当队列最大值不等于当前的输出数字时,不用管,队列中本来就没有这个数字)
if deque[0]==nums[i-k]:deque=deque[1:]
while deque and deque[-1]<nums[i]:deque=deque[:-1]
deque.append(nums[i])
res.append(deque[0])
return res
剑指 Offer 59 - II. 队列的最大值
题目

代码
class MaxQueue {
//使用一个队列与一个双向链表(保存最大值顺序)
Queue<Integer> queue;
LinkedList<Integer> deque;
public MaxQueue() {
queue=new LinkedList<>();
deque=new LinkedList<>();
}
public int max_value() {
return deque.size()==0?-1:deque.peekFirst();
}
public void push_back(int value) {
queue.add(value);
while(deque.size()!=0&&deque.peekLast()<value){
deque.removeLast();
}
deque.addLast(value);
}
public int pop_front() {
if(deque.size()!=0&&queue.peek().equals(deque.peekFirst()))
deque.removeFirst();
return queue.size()==0?-1:queue.poll();
}
}
import queue
class MaxQueue:
"""1队列+1数组"""
def __init__(self):
self.queue = queue.Queue()
self.stack = []
def max_value(self) -> int:
return self.stack[0] if self.stack else -1
def push_back(self, value: int) -> None:
self.queue.put(value)
while self.stack and self.stack[-1] < value:
self.stack.pop()
self.stack.append(value)
def pop_front(self) -> int:
if not self.stack: return -1 # 如果判断 queue 是否为空,会超时
ans = self.queue.get()
if ans == self.stack[0]:
self.stack.pop(0)
return ans
剑指 Offer 62. 圆圈中最后剩下的数字
题目

代码
class Solution {
public int lastRemaining(int n, int m) {
// 使用模拟方法暴力解答
// ArrayList<Integer> arr=new ArrayList<>();
// for(int i=0;i<n;i++){
// arr.add(i);
// }
// int idx=0;
// while(n>1){
// idx=(idx+m-1)%n;
// arr.remove(idx);
// n--;
// }
// return arr.get(0);
// 数学分析解法:最终剩下的数字的下标就是3。因为数组是从ans=0开始的,所以最终的答案就是ans=3。
// 总结一下反推的过程,就是 (当前index + m) % 上一轮剩余数字的个数
int ans=0;
for(int i=2;i<=n;i++){
ans=(ans+m)%i;
}
return ans;
}
}
浙公网安备 33010602011771号