5-栈和队列(2)
题一:【用两个栈实现队列】
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
分析:栈-先进后出 队列-先进先出
知识点:Stack API
法一:暴力-一个栈存储push的数据,一个栈pop数据。每次push前将stack2中数据添加到stack1中,每次pop数据前将stack1中数据push到stack2中。
1 import java.util.Stack;
2
3 public class Solution {
4 Stack<Integer> stack1 = new Stack<Integer>();
5 Stack<Integer> stack2 = new Stack<Integer>();
6
7 public void push(int node) {
8 while(!stack2.empty()){
9 stack1.push(stack2.pop());
10 }
11 stack1.push(node);
12 }
13
14 public int pop() {
15 while(!stack1.empty()){
16 stack2.push(stack1.pop());
17 }
18 return stack2.pop();
19 }
20 }
法二:没那么麻烦,push时直接将数据添加到stack1中;pop时先判断stack2是否为空,如果不为空直接弹出栈顶元素,如果为空,就将stack1中的元素转移到stack2中,再弹出stack2中的栈顶。
举例:
①{A},{}
②{A B},{}//直接添加B
③{},{B}//弹出,stack2为空,将stack1元素转移到stack2中再弹出栈顶
④{C D },{B}//直接添加 C D
1 import java.util.Stack;
2
3 public class Solution {
4 Stack<Integer> stack1 = new Stack<Integer>();
5 Stack<Integer> stack2 = new Stack<Integer>();
6
7 public void push(int node) {
8 stack1.push(node);
9 }
10
11 public int pop() {
12 if(stack2.empty()){
13 while(!stack1.empty()){
14 stack2.push(stack1.pop());
15 }
16 }
17 return stack2.pop();
18 }
19 }
题二:【滑动窗口的最大值】
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
法一:暴力破解-O(n*size)-看滑动数组大小,太大了效率不行
1 import java.util.*;
2 public class Solution {
3 public ArrayList<Integer> maxInWindows(int [] num, int size)
4 {
5 ArrayList<Integer> list = new ArrayList<Integer>();
6 if(size<=0) return list;
7 for(int left=0,right=size-1;right<num.length;left++,right++){
8 int max = num[left];
9 for(int i=left+1;i<=right;i++){
10 if(num[i]>max) max=num[i];
11 }
12 list.add(max);
13 }
14 return list;
15 }
16 }
法二:利用双端队列-O(N)
Step1.使用一个双端队列存储滑窗内元素的下标
value | 2 | 3 | 4 | 2 | 6 | 2 | 5 |
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
queue
Step2.若queue为空,说明刚开始滑动,将num第一个元素的索引压入队列中。
value | 2 | 3 | 4 | 2 | 6 | 2 | 5 |
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
queue
0 |
Step3.遍历num下一个元素num[1]=3,
①先判断当前索引位置减去队列最左边元素是否>=size,如果是,那么说明随着滑窗滑动,当前滑窗内的最大值滑出去了,已经不再这个滑窗内,这是需要将队列最左边元素弹出。(队列最左边为滑窗内最大值索引,判断是否有效)
②将当前元素与队列最右边的索引处的数组值对比,如果当前元素大于队列最右边对应的值,则将队列最右边的值弹出,直到找到对应值比当前元素值大的。(队列左边是最大的值,随着上述操作,会逐渐更新队列,滑出去或者新添加的值更大的话将会更新队列,保证队头对应值最大)
value | 2 | 3 | 4 | 2 | 6 | 2 | 5 |
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
1 |
value | 2 | 3 | 4 | 2 | 6 | 2 | 5 |
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
2 |
---输出4
value | 2 | 3 | 4 | 2 | 6 | 2 | 5 |
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
2 | 3 |
---输出4
value | 2 | 3 | 4 | 2 | 6 | 2 | 5 |
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
4 |
---输出6
value | 2 | 3 | 4 | 2 | 6 | 2 | 5 |
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
4 | 5 |
---输出6
value | 2 | 3 | 4 | 2 | 6 | 2 | 5 |
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
4 | 5 |
---输出6
value | 2 | 3 | 4 | 2 | 6 | 2 | 5 | 1 |
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
--当前索引处位置(7)-队列最左边(4)=size(3)--》滑出
4 | 5 | 7 |
--
5 | 7 |
--输出5
1 import java.util.*;
2 public class Solution {
3 public ArrayList<Integer> maxInWindows(int [] num, int size)
4 {
5 ArrayList<Integer> list = new ArrayList<Integer>();
6 if(num==null||size<=0) return list;
7 ArrayDeque<Integer> queue = new ArrayDeque<Integer>();
8 for(int i=0;i<num.length;i++){
9 if(queue.isEmpty()){ //只有i=0,即刚开始遍历时才会为空
10 queue.add(i);
11 }
12 if(i-queue.peekFirst()>=size){//判断队头是否还在滑窗内
13 queue.pollFirst();
14 }
15 while(!queue.isEmpty()&&num[i]>=num[queue.peekLast()]){//排除比新遍历元素还小的对应索引值
16 queue.pollLast();
17 }
18 queue.addLast(i);
19 if(i>=size-1){//从第size-1个元素开始,就要输出了
20 list.add(num[queue.peekFirst()]);
21 }
22
23 }
24 return list;
25 }
26 }
知识点:ArrayDeque API