电信保温杯笔记——代码随想录 刷题攻略 栈与队列

电信保温杯笔记——代码随想录 刷题攻略 栈与队列

  • 电信保温杯笔记——代码随想录 刷题攻略
  • 1.栈与队列:来看看栈和队列不为人知的一面
  • 2.栈与队列:我用栈来实现队列怎么样?
    • 232.用栈实现队列
  • 3.栈与队列:用队列实现栈还有点别扭
    • 225. 用队列实现栈
  • 4.栈与队列:系统中处处都是栈的应用
    • 20. 有效的括号
  • 5.栈与队列:匹配问题都是栈的强项
    • 1047. 删除字符串中的所有相邻重复项
      • 方式一:栈
      • 方式二:StringBuffer
  • 6.栈与队列:有没有想过计算机是如何处理表达式的?
    • 150. 逆波兰表达式求值
  • 7.栈与队列:滑动窗口里求最大值引出一个重要数据结构
    • 239. 滑动窗口最大值
      • 方式一:储存数值
      • 方式二:储存下标
  • 8.栈与队列:求前 K 个高频元素和队列有啥关系?
    • 347.前 K 个高频元素
  • 9.栈与队列:总结篇!

电信保温杯笔记——代码随想录 刷题攻略

代码随想录 刷题攻略
电信保温杯笔记——代码随想录 刷题攻略

1.栈与队列:来看看栈和队列不为人知的一面

讲义地址

2.栈与队列:我用栈来实现队列怎么样?

讲义地址

232.用栈实现队列

leetcode地址

queue.push(x) 的实现:
电信保温杯笔记——代码随想录 刷题攻略 栈与队列_第1张图片

class MyQueue {
    Stack stack = new Stack();
    public MyQueue() {

    }

    public void push(int x) {
        Stack temp = new Stack();
        while (!stack.empty()){
            temp.push(stack.pop());
        }
        stack.push(x);
        while (!temp.empty()){
            stack.push(temp.pop());
        }
    }

    public int pop() {
        return (int) stack.pop();
    }

    public int peek() {
        return (int) stack.peek();
    }

    public boolean empty() {
        return stack.empty();
    }
}

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue obj = new MyQueue();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.peek();
 * boolean param_4 = obj.empty();
 */

电信保温杯笔记——代码随想录 刷题攻略 栈与队列_第2张图片

3.栈与队列:用队列实现栈还有点别扭

讲义地址

225. 用队列实现栈

leetcode地址

stack.push(x) 的实现:
电信保温杯笔记——代码随想录 刷题攻略 栈与队列_第3张图片

class MyStack {
    Queue queue = new LinkedList();
    public MyStack() {

    }

    public void push(int x) {
        Queue temp = new LinkedList();
        while (!queue.isEmpty()){
            temp.add(queue.poll());
        }
        queue.add(x);
        while (!temp.isEmpty()){
            queue.add(temp.poll());
        }
    }

    public int pop() {
        return (int) queue.poll();
    }

    public int top() {
        return (int) queue.peek();
    }

    public boolean empty() {
        return queue.isEmpty();
    }
}

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack obj = new MyStack();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.top();
 * boolean param_4 = obj.empty();
 */

电信保温杯笔记——代码随想录 刷题攻略 栈与队列_第4张图片

4.栈与队列:系统中处处都是栈的应用

讲义地址

20. 有效的括号

leetcode地址

有三种不匹配的情况

class Solution {
    public boolean isValid(String s) {
        int len = s.length();
        if (len % 2 == 1){
            return false;
        }
        HashMap<Character, Character> map = new HashMap<>();
        map.put(']', '[');
        map.put('}', '{');
        map.put(')', '(');
        Stack stack = new Stack();
        for (int i = 0; i < len; i++) {
            char temp = s.charAt(i);
            if(!stack.empty() && map.get(temp) == stack.peek()){
                stack.pop();
            }else{
                stack.push(temp);
            }
        }
        return stack.empty();
    }
}

电信保温杯笔记——代码随想录 刷题攻略 栈与队列_第5张图片

5.栈与队列:匹配问题都是栈的强项

讲义地址

1047. 删除字符串中的所有相邻重复项

leetcode地址

方式一:栈

class Solution {
    public String removeDuplicates(String s) {
        int len = s.length();
        Stack<Character> stack = new Stack();
        for (int i = 0; i < len; i++) {
            char temp = s.charAt(i);
            if (!stack.empty() && temp == stack.peek()){
                stack.pop();
            }else{
                stack.push(temp);
            }
        }
        
        String res = "";
        while (!stack.empty()){
            res = stack.pop() + res;
        }
        return res;
    }
}

电信保温杯笔记——代码随想录 刷题攻略 栈与队列_第6张图片
效率低

方式二:StringBuffer

class Solution {
    public String removeDuplicates(String s) {
        StringBuffer res = new StringBuffer();
        int top = -1;
        int len = s.length();
        for (int i = 0; i < len; i++) {
            char temp = s.charAt(i);
            if (top >=0 && temp == res.charAt(top)){
                res.deleteCharAt(top);
                top--;
            }else{
                res.append(temp);
                top++;
            }
        }
        return res.toString();
    }
}

电信保温杯笔记——代码随想录 刷题攻略 栈与队列_第7张图片
使用StringBuffer作为栈。

6.栈与队列:有没有想过计算机是如何处理表达式的?

讲义地址

150. 逆波兰表达式求值

leetcode地址

class Solution {
    public int evalRPN(String[] tokens) {
        int len = tokens.length;
        Set<String> set = new HashSet<>();
        set.add("+");
        set.add("-");
        set.add("*");
        set.add("/");
        Stack<Integer> stack = new Stack<>();
        for (int i = 0; i < len; i++) {
            String temp = tokens[i];
            if (!stack.empty() && set.contains(temp)){
                int n = stack.pop();
                int m = stack.pop();
                stack.push(calculate(m, n, temp));
            }else {
                stack.push(Integer.valueOf(temp));
            }
        }
        return stack.pop();
    }

    public int calculate(int m, int n, String s){
        int res = 0;
        if ("+".equals(s)){
            res = m + n;
        }
        if ("-".equals(s)){
            res = m - n;
        }
        if ("*".equals(s)){
            res = m * n;
        }
        if ("/".equals(s)){
            res = m / n;
        }
        return res;
    }
}

电信保温杯笔记——代码随想录 刷题攻略 栈与队列_第8张图片

7.栈与队列:滑动窗口里求最大值引出一个重要数据结构

讲义地址

239. 滑动窗口最大值

leetcode地址

方式一:储存数值

//解法一
//自定义数组
class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int len = nums.length;
        if (len == 1) {
            return nums;
        }
        //存放结果元素的数组
        int[] res = new int[len - k + 1];
        //自定义队列
        MyQueue myQueue = new MyQueue();
        //先将前k的元素放入队列
        for (int i = 0; i < k; i++) {
            myQueue.add(nums[i]);
        }
        res[0] = myQueue.peek();
        int index = 1;
        for (int i = k; i < len; i++) {
            //滑动窗口移除最前面的元素,移除是判断该元素是否放入队列
            myQueue.poll(nums[i - k]);
            //滑动窗口加入最后面的元素
            myQueue.add(nums[i]);
            //记录对应的最大值
            res[index] = myQueue.peek();
            index++;
        }
        return res;
    }

    class MyQueue {
        Deque<Integer> deque = new LinkedList<>();

        //弹出元素时,比较当前要弹出的数值是否等于队列出口的数值,如果相等则弹出
        //同时判断队列当前是否为空
        void poll(int val) {
            if (!deque.isEmpty() && val == deque.peek()) {
                deque.poll();
            }
        }

        //添加元素时,如果要添加的元素大于入口处的元素,就将入口元素弹出
        //保证队列元素单调递减
        //比如此时队列元素3,1,2将要入队,比1大,所以1弹出,此时队列:3,2
        void add(int val) {
            while (!deque.isEmpty() && val > deque.getLast()) {
                deque.removeLast();
            }
            deque.add(val);
        }

        //队列队顶元素始终为最大值
        int peek() {
            return deque.peek();
        }
    }
}

电信保温杯笔记——代码随想录 刷题攻略 栈与队列_第9张图片

方式二:储存下标

//解法二
//利用双端队列手动实现单调队列
/**
 * 用一个单调队列来存储对应的下标,每当窗口滑动的时候,直接取队列的头部指针对应的值放入结果集即可
 * 单调队列类似 (tail -->) 3 --> 2 --> 1 --> 0 (--> head) (右边为头结点,元素存的是下标)
 */
class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        ArrayDeque<Integer> deque = new ArrayDeque<>();
        int n = nums.length;
        int[] res = new int[n - k + 1];
        int idx = 0;
        for(int i = 0; i < n; i++) {
            // 根据题意,i为nums下标,是要在[i - k + 1, i] 中选到最大值,只需要保证两点
            // 1.队列头结点需要在[i - k + 1, i]范围内,不符合则要弹出
            while(!deque.isEmpty() && deque.peek() < i - k + 1){
                deque.poll();
            }
            // 2.既然是单调,就要保证每次放进去的数字要比末尾的都大,否则也弹出
            while(!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {
                deque.pollLast();
            }

            deque.offer(i);

            // 因为单调,当i增长到符合第一个k范围的时候,每滑动一步都将队列头节点放入结果就行了
            if(i >= k - 1){
                res[idx++] = nums[deque.peek()];
            }
        }
        return res;
    }
}

电信保温杯笔记——代码随想录 刷题攻略 栈与队列_第10张图片

8.栈与队列:求前 K 个高频元素和队列有啥关系?

讲义地址

347.前 K 个高频元素

leetcode地址

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        int len = nums.length;
        int[] res = new int[k];
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < len; i++) {
            int temp = nums[i];
            map.put(temp, map.getOrDefault(temp, 0) + 1);
        }
        // 根据map的value值正序排,相当于一个小顶堆
        Set<Map.Entry<Integer, Integer>> set = map.entrySet();
        PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>(new Comparator<Map.Entry<Integer, Integer>>() {
            @Override
            public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> t1) {
                return o1.getValue() - t1.getValue();
            }
        });

        for (Map.Entry<Integer, Integer> entry : set) {
            queue.add(entry);
            if (queue.size() > k) {
                // 频率小的弹出
                queue.poll();
            }
        }

        for (int i = k - 1; i >= 0; i--) {
            res[i] = queue.poll().getKey();
        }
        return res;
    }
}

电信保温杯笔记——代码随想录 刷题攻略 栈与队列_第11张图片

9.栈与队列:总结篇!

讲义地址

你可能感兴趣的:(算法与数据结构,leetcode,算法,职场和发展)