栈与队列
方法:使用两个栈,一个输入栈,一个输出栈
其中需要注意的点是,在进行pop()和peek()操作时,要先判断stackOut空了,再把stackIn的数倒进去
代码实现为:
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() {
return stackOut.isEmpty() && stackIn.isEmpty();
}
private void dumpStackIn(){
if(!stackOut.isEmpty()){
return;
}
while(!stackIn.isEmpty()){
stackOut.push(stackIn.pop());
}
}
}
/**
* 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();
*/
添加元素:栈 - push() 队列 - push()插到队列开头 offer()插到队列末尾
查看元素:栈 - peek() 队列 - top()/peek()
移除元素: 栈 - pop() 队列 - poll() 确定队列不为空也可使用pop()
方法:使用两个Deque实现,其中一个作为辅助队列,另一个维护和栈中元素一样的队列
代码实现为:
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());
}
//交换,元素都放到queue1中
Queue tmpQueue = queue1;
queue1 = queue2;
queue2 = tmpQueue;
}
public int pop() {
return queue1.poll();
}
public int top() {
return queue1.peek();
}
public boolean empty() {
return queue1.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();
*/
注意,此处向栈中存入左括号,使用的是push(),因为要将其放在队列的开头
代码实现为:
class Solution {
public boolean isValid(String s) {
Map<Character,Character> hashmap = new HashMap<>();
hashmap.put('[',']');
hashmap.put('{','}');
hashmap.put('(',')');
Deque<Character> stack = new LinkedList<>();
// Stack<Character> stack = new Stack<>();
//一般来说,在Java中推荐使用Deque接口及其实现类来代替Stack类
//因为Deque接口提供了更加灵活和现代化的栈操作方式,同时也避免了Stack类可能存在的一些问题。
for(char c:s.toCharArray()){
//遇到左括号,进栈
if(hashmap.containsKey(c)){
stack.push(c);
}else{
if(stack.isEmpty()){
return false;
}else if(c!=hashmap.get(stack.peek())){
return false;
}
stack.pop();
}
}
return stack.isEmpty();
}
}
注意最后要把字符串反转
代码实现为:
class Solution {
public String removeDuplicates(String s) {
Deque<Character> stack = new LinkedList<>();
for(char c:s.toCharArray()){
if(stack.isEmpty() || c!=stack.peek()){
stack.push(c);
}else{
stack.pop();
}
}
StringBuilder sb = new StringBuilder();
while(!stack.isEmpty()){
sb.append(stack.pop());
}
return sb.reverse().toString();
}
}
注意:1、比较值是否相等使用equals()方法
2、减法和除法注意特殊处理
代码实现为:
class Solution {
public int evalRPN(String[] tokens) {
Deque<Integer> stack = new LinkedList<>();
for(String s:tokens){
//注意减法和除法需要特殊处理!
if(s.equals("+")){
stack.push(stack.pop()+stack.pop());
}else if(s.equals("-")){
stack.push(-stack.pop()+stack.pop());
}else if(s.equals("*")){
stack.push(stack.pop()*stack.pop());
}else if(s.equals("/")){
int tmp1 = stack.pop();
int tmp2 = stack.pop();
stack.push(tmp2/tmp1);
}else{
stack.push(Integer.valueOf(s));
}
}
return stack.pop();
}
}
难点:自定义队列
代码实现为:
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
MyQueue myQueue = new MyQueue();
int len = nums.length-k+1;
int[] res = new int[len];
int num = 0;
for(int i = 0;i<k;i++){
myQueue.add(nums[i]);
}
res[num++] = myQueue.peek();
for(int i = k;i<nums.length;i++){
//滑动窗口移除最前面的元素
myQueue.poll(nums[i-k]);
//滑动窗口加入最后面的元素
myQueue.add(nums[i]);
//记录对应的最大值
res[num++] = myQueue.peek();
}
return res;
}
}
//自定义数组
class MyQueue{
Deque<Integer> deque = new LinkedList<>();
//移除元素
void poll(int val){
//注意为if而不是while,因为只移除队列最左的一个数(滑动窗口移动)
if(!deque.isEmpty() && val==deque.peek()){
deque.poll();
}
}
//添加元素
//注意循环为while循环,因为要一直执行循环体,直到前面的数都比新加的数大为止
void add(int val){
while(!deque.isEmpty() && val>deque.getLast()){
deque.removeLast();
}
deque.add(val);
}
//维护队列队顶元素为最大值
int peek(){
return deque.peek();
}
}
重点:使用优先级队列中的大顶堆
代码实现为:
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> hashmap = new HashMap<>();
for(int num:nums){
hashmap.put(num,hashmap.getOrDefault(num,0)+1);
}
//使用大顶堆:1、默认为小顶堆,故要颠倒次序 2、利用第二个元素即出现次数进行排序
//int[0]表示键,int[1]表示值
PriorityQueue<int[]>pq = new PriorityQueue<>((pair1,pair2)->pair2[1]-pair1[1]);
//遍历哈希表存储的键值对
for(Map.Entry<Integer,Integer>entry:hashmap.entrySet()){
pq.add(new int[]{entry.getKey(),entry.getValue()});
}
int[] res = new int[k];
for(int i = 0;i<k;i++){
res[i] = pq.poll()[0];
}
return res;
}
}