算法-栈与队列

一、理论基础

  1. 队列:先进先出
  2. 栈:先进后出

二、用栈实现队列

  1. 题目
    1. 用栈实现队列
  2. 思路
    1. 在push数据的时候,只要数据放进输入栈就好。
    2. pop的时候,操作就复杂一些,输出栈如果为空,就把进栈数据全部导入进来(注意是全部导入),再从出栈弹出数据,如果输出栈不为空,则直接从出栈弹出数据就可以了。
  3. 代码
    class MyQueue {
    
        private int size;
        private Deque<Integer> in;
        private Deque<Integer> out;
    
        public MyQueue() {
            this.size = 0;
            this.in = new LinkedList<>();
            this.out = new LinkedList<>();
        }
    
        public void push(int x) {
            size++;
            in.push(x);
        }
    
        public int pop() {
            size--;
            if (out.isEmpty()) {
                while (!in.isEmpty()) {
                    out.push(in.pop());
                }
            }
            return out.pop();
        }
    
        public int peek() {
            int pop = this.pop();
            out.push(pop);
            size++;
            return pop;
        }
    
        public boolean empty() {
            return size == 0;
        }
    }

三、用队列实现栈

  1. 题目
    1. 用队列实现栈
  2. 思路
    1. 一个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时再去弹出元素就是栈的顺序了。
  3. 代码
    class MyStack {
        // 先进后出
        private Deque<Integer> deque;
    
        public MyStack() {
            this.deque = new LinkedList<>();
        }
    
        public void push(int x) {
            deque.offer(x);
        }
    
        public int pop() {
            for (int i = deque.size(); i > 1; i--) {
                deque.offer(deque.poll());
            }
            return deque.poll();
        }
    
        public int top() {
            int pop = this.pop();
            deque.offer(pop);
            return pop;
        }
    
        public boolean empty() {
            return deque.isEmpty();
        }
    }

四、简化路径

  1. 题目
    1. path = "/a/./b/../../c/", 结果:"/c"
  2. 思路
  3. 代码
    class Solution {
        public String simplifyPath(String path) {
            Deque<String> deque = new LinkedList<>();
            // ..弹出
            String[] str = path.split("/");
            for (String s : str) {
                if (!deque.isEmpty() && "..".equals(s)) {
                    deque.pop();
                } else if (!".".equals(s) && !"..".equals(s) && !"".equals(s)) {
                    deque.push(s);
                }
            }
            StringBuilder sb = new StringBuilder();
            while (!deque.isEmpty()) {
                sb.insert(0, "/" + deque.pop());
            }
            return sb.length() == 0 ? "/" : sb.toString();
        }
    }

五、有效括号

  1. 题目
    1. 给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。
  2. 思路
    1. 遍历的过程中,匹配不上,返回false
    2. 遍历的过程中,栈空了,返回false
    3. 遍历完,栈不为空,发明会false
  3. 代码
    class Solution {
        public boolean isValid(String s) {
            Deque<Character> deque = new LinkedList<>();
            for (char ch : s.toCharArray()) {
                if (ch == '(' || ch == '{' || ch == '[') {
                    deque.push(ch);
                }
                if (deque.isEmpty() || ch == ')' && deque.pop() != '('
                        || ch == '}' && deque.pop() != '{'
                        || ch == ']' && deque.pop() != '[') {
                    return false;
                }
            }
            return deque.isEmpty();
        }
    }

六、删除字符串中的所有相邻重复项

  1. 题目
    1. 给出由小写字母组成的字符串 S重复项删除操作会选择两个相邻且相同的字母,并删除它们。在 S 上反复执行重复项删除操作,直到无法继续删除。

  2. 思路
    1. 遇到重复,则弹出
  3. 代码
    class Solution {
        public String removeDuplicates(String s) {
            Deque<Character> deque = new LinkedList<>();
            for (char ch : s.toCharArray()) {
                if (!deque.isEmpty() && ch == deque.peek()) {
                    deque.pop();
                    continue;
                }
                deque.push(ch);
            }
            StringBuilder sb = new StringBuilder();
            while (!deque.isEmpty()) {
                sb.append(deque.pop());
            }
            return sb.reverse().toString();
        }
    }

七、逆波兰表达式

  1. 题目
    1. 给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

      请你计算该表达式。返回一个表示表达式值的整数。

  2. 思路
  3. 代码
    class Solution {
        public int evalRPN(String[] tokens) {
            Deque<Integer> deque = new LinkedList<>();
            String s = "+-*/";
            for (String str : tokens) {
                if (s.contains(str)) {
                    int pop = deque.pop();
                    int push = deque.pop();
                    if ("+".equals(str)) {
                        push += pop;
                    }
                    if ("-".equals(str)) {
                        push -= pop;
                    }
                    if ("*".equals(str)) {
                        push *= pop;
                    }
                    if ("/".equals(str)) {
                        push /= pop;
                    }
                    deque.push(push);
                    continue;
                }
                deque.push(Integer.valueOf(str));
            }
            return deque.pop();
        }
    }

八、滑动窗口最大值

  1. 题目
    1. 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

      返回 滑动窗口中的最大值 

  2. 思路
    1. 维护递减队列
  3. 代码
    class Solution {
        public int[] maxSlidingWindow(int[] nums, int k) {
            // 维持递增队列(队尾->队首)
            List<Integer> list = new ArrayList<>();
            Deque<Integer> deque = new LinkedList<>();
            int slow = 0;
            for (int fast = 0; fast < nums.length; fast++) {
                // poll
                if (fast - slow + 1 > k && deque.peek() == nums[slow++]) {
                    deque.poll();
                }
                // add
                while (!deque.isEmpty() && deque.peekLast() < nums[fast]) {
                    deque.pollLast();
                }
                deque.offer(nums[fast]);
                if (fast - slow + 1 == k) {
                    list.add(deque.peek());
                }
            }
            return list.stream().mapToInt(i -> i).toArray();
        }
    }

九、前k个高频元素

  1. 题目
    1. 给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
  2. 思路
    1. 根据频率排序
  3. 代码
    class Solution {
        public int[] topKFrequent(int[] nums, int k) {
            Map<Integer, Integer> map = new HashMap<>();
            for (int num : nums) {
                map.put(num, map.getOrDefault(num, 0) + 1);
            }
            PriorityQueue<Map.Entry<Integer, Integer>> pq = new PriorityQueue<>(new Comparator<>() {
                @Override
                public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
                    return o2.getValue() - o1.getValue();
                }
            });
            for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
                pq.offer(entry);
            }
            List<Integer> list = new ArrayList<>();
            while (k-- > 0) {
                list.add(pq.poll().getKey());
            }
            return list.stream().mapToInt(i -> i).toArray();
        }
    }

十、总结

未完待续......

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值