剑指Offer-学习计划(五)栈与队列

剑指 Offer 09. 用两个栈实现队列

剑指 Offer 30. 包含min函数的栈

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

剑指 Offer 59 - II. 队列的最大值

要点:

1. 栈和队列本身都属于限制型的数据结构,有各自的定义,也有可以混淆的部分

2. 他们也是源自数组和链表的一种延伸结构,比如数组实现的栈成为顺序栈,链表实现的栈成为链式栈

3.我们可以根据两者的定义去理解他们,但是实际使用其实没必要给他们彻底区分,比如Queue、Deque这些,为什么不能表达栈

题目一:这道题很实在,就是考一考对栈,队列,基础结构等等的一些理解和用法

剑指 Offer 09. 用两个栈实现队列

用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

示例 1:

输入:
["CQueue","appendTail","deleteHead","deleteHead","deleteHead"]
[[],[3],[],[],[]]
输出:[null,null,3,-1,-1]

示例 2:

输入:
["CQueue","deleteHead","appendTail","appendTail","deleteHead","deleteHead"]
[[],[],[5],[2],[],[]]
输出:[null,-1,null,null,5,2]

解法一:我很喜欢这个解法,看着deleteHead稍微显得复杂了一点,但是他陈述的很完整

static class CQueue2 {

        LinkedList stack1;
        LinkedList stack2;

        public CQueue2() {
            stack1 = new LinkedList<>();
            stack2 = new LinkedList<>();
        }

        public void appendTail(int value) {
            stack1.push(value);
        }

        public int deleteHead() {
            if (stack2.isEmpty()){
                if (stack1.isEmpty())return -1;
                while(!stack1.isEmpty()){
                    stack2.push(stack1.pop());
                }
                return stack2.pop();
            }else {
                return stack2.pop();
            }
        }
    }

 解法二:前面用Deque接也可以反正是自己的实现类,其实我们JAVA的结构类里面已经包含了这些方法

static class CQueue1 {

        Deque stack1;
        Deque stack2;
        // LinkedList q1;
        // LinkedList q2;

        public CQueue1() {
            stack1 = new LinkedList<>();
            stack2 = new LinkedList<>();
        }

        public void appendTail(int value) {
            stack1.addLast(value);
        }

        public int deleteHead() {
            if (stack1.isEmpty()) return -1;
            return stack1.removeFirst();
        }
    }

题目二:

剑指 Offer 30. 包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。

示例:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.min();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.min();   --> 返回 -2.

提示:

  1. 各函数的调用总次数不超过 20000 次

解法:这道题很简单,首先把我们常用的Node节点实现出来,之后按照所需方法逐个实现即可,注意节点里面该有的val,min,next这些都要有

class MinStack {

        private Node head;

        /** initialize your data structure here. */
        public MinStack() {

        }

        public void push(int x) {
            if (head == null)
                head = new Node(x,x,null);
            else
                head = new Node(x,Math.min(head.min,x),head);
        }

        public void pop() {
            head = head.next;
        }

        public int top() {
            return head.val;
        }

        public int min() {
            return head.min;
        }

        private class Node{
            int val;
            int min;
            Node next;

            public Node(int val, int min, Node next) {
                this.val = val;
                this.min = min;
                this.next = next;
            }
        }

    }

题目三:

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

给定一个数组 nums 和滑动窗口的大小 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

 解法一:先简单校验一下,之后把数组搞出来,使用ArrayDeque,因为结合滑动窗口,所以需要i,j一起在循环里面转悠

public int[] maxSlidingWindow(int[] nums, int k) {
        if (nums == null || nums.length == 0) {
            return new int[0];
        }
        int[] res = new int[nums.length - k + 1];
        Deque queue = new ArrayDeque<>();
        for (int i = 0, j = 0; i < nums.length; i++) {
            if (!queue.isEmpty() && i-queue.peek() >= k){
                queue.poll();
            }
            while (!queue.isEmpty() && nums[i]>nums[queue.peekFirst()]){
                queue.pollLast();
            }
            queue.offer(i);
            if (i>=k-1){
                res[j++] = nums[queue.peek()];
            }
        }
        return res;
    }

题目四:又是实现队列

请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_valuepush_back 和 pop_front 的均摊时间复杂度都是O(1)。

若队列为空,pop_front 和 max_value 需要返回 -1

示例 1:

输入: 
["MaxQueue","push_back","push_back","max_value","pop_front","max_value"]
[[],[1],[2],[],[],[]]
输出: [null,null,null,2,1,2]

示例 2:

输入: 
["MaxQueue","pop_front","max_value"]
[[],[],[]]
输出: [null,-1,-1]

解法一:跟第一个题很类似,但是需要考虑最大值的问题

class MaxQueue {
    private Deque q1;
    private Deque q2;

    public MaxQueue() {
        q1 = new ArrayDeque<>();
        q2 = new ArrayDeque<>();
    }

    public int max_value() {
        return q1.isEmpty() ? -1 : q2.peek();
    }

    public void push_back(int value) {
        q1.offer(value);
        while (!q2.isEmpty() && value > q2.peekLast()){
            q2.pollLast();
        }
        q2.offer(value);
    }

    public int pop_front() {
        if (q1.isEmpty()){
            return -1;
        }
        int val = q1.pop();
        if (q2.peek() == val){
            q2.pop();
        }
        return val;
    }
}

你可能感兴趣的:(算法笔记,数据结构与算法学习,学习,java)