算法 栈与队列 hiriki 2022-12-20 2022-12-20 232.用栈实现队列 leetcode题目链接
使用栈实现队列的下列操作:
push(x) — 将一个元素放入队列的尾部。
pop() — 从队列首部移除元素。
peek() — 返回队列首部的元素。
empty() — 返回队列是否为空。
思路草稿
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 class MyQueue { Stack<Integer> stackIn; Stack<Integer> stackOut; public MyQueue () { stackIn = new Stack <>(); stackOut = new Stack <>(); } public void push (int x) { stackIn.push(x); } public int pop () { dumpStackIn(); return stackOut.pop(); } public int peek () { dumpStackIn(); return stackOut.peek(); } public boolean empty () { if (stackIn.isEmpty()&&stackOut.isEmpty()){ return true ; } return false ; } private void dumpStackIn () { if (!stackOut.isEmpty()){ return ; } while (!stackIn.isEmpty()){ stackOut.push(stackIn.pop()); } } }
225.用队列实现栈 leetcode题目链接
使用队列实现栈的下列操作:
push(x) — 元素 x 入栈
pop() — 移除栈顶元素
top() — 获取栈顶元素
empty() — 返回栈是否为空
思路草稿 一个队列
两个队列
题解 一个队列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class MyStack { Queue<Integer> queue; public MyStack () { queue = new LinkedList <>(); } public void push (int x) { queue.offer(x); int size = queue.size(); while (size-->1 ){ queue.offer(queue.poll()); } } public int pop () { return queue.poll(); } public int top () { return queue.peek(); } public boolean empty () { return queue.isEmpty(); } }
两个队列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 class MyStack { Queue<Integer> queue1; Queue<Integer> queue2; public MyStack () { queue1 = new LinkedList <>(); queue2 = new LinkedList <>(); } public void push (int x) { queue2.offer(x); while (!queue1.isEmpty()){ queue2.offer(queue1.poll()); } Queue<Integer> temp; temp = queue1; queue1 = queue2; queue2 = temp; } public int pop () { return queue1.poll(); } public int top () { return queue1.peek(); } public boolean empty () { return queue1.isEmpty(); } }
20.有效的括号 leetcode题目链接
给定一个只包括 ‘(‘,’)’,’{‘,’}’,’[‘,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
思路草稿
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution { public boolean isValid (String s) { Stack<Character> stack = new Stack <>(); for (int i = 0 ;i<s.length();i++){ char ch = s.charAt(i); if (ch == '(' ){ stack.push(')' ); } else if (ch == '[' ){ stack.push(']' ); } else if (ch == '{' ){ stack.push('}' ); } else if (stack.isEmpty() || stack.peek()!=ch){ return false ; } else { stack.pop(); } } return stack.isEmpty(); } }
1047. 删除字符串中的所有相邻重复项 leetcode题目链接
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
示例:
输入:”abbaca”
输出:”ca”
解释:例如,在 “abbaca” 中,我们可以删除 “bb” 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 “aaca”,其中又只有 “aa” 可以执行重复项删除操作,所以最后的字符串为 “ca”。
思路草稿
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution { public String removeDuplicates (String s) { Stack<Character> stack = new Stack <>(); for (int i = 0 ;i<s.length();i++){ char ch = s.charAt(i); if (stack.isEmpty() || stack.peek()!=ch){ stack.push(ch); } else { stack.pop(); } } String res = "" ; while (!stack.isEmpty()){ res = stack.pop()+res; } return res; } }
150. 逆波兰表达式求值 leetcode题目链接
根据 逆波兰表示法,求表达式的值。
有效的运算符包括 + , - , * , / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
整数除法只保留整数部分。 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
思路草稿
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution { public int evalRPN (String[] tokens) { Stack<Integer> stack = new Stack <>(); for (String token : tokens){ if ("+" .equals(token)){ stack.push(stack.pop()+stack.pop()); } else if ("-" .equals(token)){ stack.push(-stack.pop()+stack.pop()); } else if ("*" .equals(token)){ stack.push(stack.pop()*stack.pop()); } else if ("/" .equals(token)){ int temp1 = stack.pop(); int temp2 = stack.pop(); stack.push(temp2/temp1); } else { stack.push(Integer.valueOf(token)); } } return stack.pop(); } }
239. 滑动窗口最大值 leetcode题目链接
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
思路草稿
主要思想是队列没有必要维护窗口里的所有元素,只需要维护有可能成为窗口里最大值的元素就可以了,同时保证队列里的元素数值是由大到小的。
那么这个维护元素单调递减的队列就叫做单调队列,即单调递减或单调递增的队列。
设计单调队列的时候,pop和push操作要保持如下规则:
pop(value):如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作
push(value):如果push的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 class MyDequeue { Deque<Integer> dequeue = new LinkedList <>(); void pop (int val) { if (!dequeue.isEmpty()&&dequeue.peek()==val){ dequeue.poll(); } } void push (int val) { while (!dequeue.isEmpty()&&val>dequeue.getLast()){ dequeue.removeLast(); } dequeue.add(val); } int maxVal () { return dequeue.peek(); } } class Solution { public int [] maxSlidingWindow(int [] nums, int k) { if (nums.length==1 ){ return nums; } int len = nums.length - k + 1 ; int [] res = new int [len]; int count = 0 ; MyDequeue myDequeue = new MyDequeue (); for (int i = 0 ;i<k;i++){ myDequeue.push(nums[i]); } res[count++] = myDequeue.maxVal(); for (int i = k; i<nums.length;i++){ myDequeue.pop(nums[i-k]); myDequeue.push(nums[i]); res[count++] = myDequeue.maxVal(); } return res; } }
347.前 K 个高频元素 leetcode题目链接
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
思路草稿
优先级队列就是一个披着队列外衣的堆 ,因为优先级队列对外接口只是从队头取元素,从队尾添加元素,再无其他取元素的方式,看起来就是一个队列,且内部元素是自动依照元素的权值排列 。
堆是一棵完全二叉树,树中每个结点的值都不小于(或不大于)其左右孩子的值。 如果父亲结点是大于等于左右孩子就是大顶堆,小于等于左右孩子就是小顶堆。
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 class Solution { public int [] topKFrequent1(int [] nums, int k) { Map<Integer,Integer> map = new HashMap <>(); for (int num:nums){ map.put(num,map.getOrDefault(num,0 )+1 ); } PriorityQueue<int []> pq = new PriorityQueue <>((pair1, pair2)->pair2[1 ]-pair1[1 ]); for (Map.Entry<Integer,Integer> entry:map.entrySet()){ pq.add(new int []{entry.getKey(),entry.getValue()}); } int [] ans = new int [k]; for (int i=0 ;i<k;i++){ ans[i] = pq.poll()[0 ]; } return ans; } public int [] topKFrequent2(int [] nums, int k) { Map<Integer,Integer> map = new HashMap <>(); for (int num:nums){ map.put(num,map.getOrDefault(num,0 )+1 ); } PriorityQueue<int []> pq = new PriorityQueue <>((pair1,pair2)->pair1[1 ]-pair2[1 ]); for (Map.Entry<Integer,Integer> entry:map.entrySet()){ if (pq.size()<k){ pq.add(new int []{entry.getKey(),entry.getValue()}); }else { if (entry.getValue()>pq.peek()[1 ]){ pq.poll(); pq.add(new int []{entry.getKey(),entry.getValue()}); } } } int [] ans = new int [k]; for (int i=k-1 ;i>=0 ;i--){ ans[i] = pq.poll()[0 ]; } return ans; } }