chenheng199898

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

剑指 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;
    }
}
posted on 2020-08-06 15:43  chenheng199898  阅读(56)  评论(0)    收藏  举报