目录
一、基础概念
什么是栈(stack)呢?大概就是一个类似于弹夹的东西,懂得都懂。属于FILO(先进后出)或者LIFO(后进先出)模式的一种容器结构。顶部元素叫栈顶,底部元素叫栈底。栈的常见操作有1、压栈(push)2、弹栈(pop)3、查看栈顶元素(peek)4、查看元素个数(size)等。
队列(Queue),顾名思义就是数据像排队一样,一个一个来。即FIFO(先进先出)模式的一种容器结构。队列的开头称为队首(head),结尾称为队尾(tail)。队列常见的操作有1、放入队列尾部(offer)2、取出队首元素(poll)3、查看队首元素(peek)4、查看元素个数(size)等。
队列还有一种称为双端队列(Deque)。就是两端都允许进出,但是不允许中间进出的队列。
二、基础练习
1、.括号匹配问题
思路:就是说每一个左括号得匹配一个右括号,否则就输出false。我们可以遍历将字符放入栈中,如果放入的字符为左括号,就继续,如果为右括号,就说明栈中一定要有匹配的左括号,否则就输出false,所以此时我们出栈查看是否匹配。如果遍历结束栈中还有元素,就输出false没有就输出true。
import java.util.*;
class Solution {
public boolean pipei(char a,char b){
if(a=='('&&b==')'){
return true;
}else if(a=='['&&b==']'){
return true;
}else return a == '{' && b == '}';
}
public boolean isValid(String s) {
Deque<Character> stack=new LinkedList<>();
char[] c=s.toCharArray();
for( char c1: c){
if(c1=='('||c1=='['||c1=='{'){
stack.push(c1);
}else{
if(stack.isEmpty()){
return false;
}else{
if(!pipei(stack.pop(),c1)){
return false;
}
}
}
}
return stack.isEmpty();
}
}
2、用队列实现栈
思路:我们需要用两个队列实现一个栈,这个问题就简单了。我们只要用一个队列用来存储,另外一个队列用来做中间转存即可。
import java.util.*;
class MyStack {
public final Queue<Integer> queue1 =new LinkedList<>();
public final Queue<Integer> queue2 =new LinkedList<>();
public MyStack() {
}
public void push(int x) {
queue1.offer(x);
}
public int pop() {
int size=queue1.size();
for(int i=0;i<size-1;i++){
int p=queue1.poll();
queue2.offer(p);
}
int p=queue1.poll();
for(int i=0;i<size-1;i++){
queue1.offer(queue2.poll());
}
return p;
}
public int top() {
int size=queue1.size();
for(int i=0;i<size-1;i++){
int p=queue1.poll();
queue2.offer(p);
}
int p=queue1.poll();
for(int i=0;i<size-1;i++){
queue1.offer(queue2.poll());
}
queue1.offer(p);
return p;
}
public boolean empty() {
return queue1.isEmpty();
}
}
3、实现一个最小栈
思路:我们可以以空间换时间,就是再用一个栈来进行最小值的存储。
import java.util.*;
class MinStack {
Deque<Integer> stack1=new LinkedList<>();
Deque<Integer> stack2=new LinkedList<>();
public MinStack() {
}
public void push(int val) {
stack1.push(val);
if(stack2.isEmpty()){
stack2.push(val);
}else{
if(stack2.peek()<=val){
stack2.push(stack2.peek());
}else{
stack2.push(val);
}
}
}
public void pop() {
stack1.pop();
stack2.pop();
}
public int top() {
return stack1.peek();
}
public int getMin() {
return stack2.peek();
}
}
4、设计循环队列
思路:首先我们需要知道什么是循环队列。循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被 " 连接 " 在队首之后以形成一个循环。这样就可以更加充分的利用队列的空间。关键在于,当我此时到了本来的队尾的时候,继续要添加的时候,此时队尾转移到原来的队首。当我们在列表的开始位置,要进行删除时,此时队首的位置转移到队尾。
关键在于如何实现这种队首到队尾或者队尾到队首的转变。我们可以通过+length然后取模的操作来完成。
class MyCircularQueue {
int[] array;
int frontIndex;
int rearIndex;
int size;
public MyCircularQueue(int k) {
array=new int[k];
}
public boolean enQueue(int value) {
if(isFull()){
return false;
}else{
array[rearIndex]=value;
rearIndex=(rearIndex+1)%array.length;
}
size++;
return true;
}
public boolean deQueue() {
if(isEmpty()){
return false;
}
frontIndex=(frontIndex+1)%array.length;
size--;
return true;
}
public int Front() {
if(isEmpty()){
return -1;
}else{
return array[frontIndex];
}
}
public int Rear() {
if(isEmpty()){
return -1;
}else{
return array[(rearIndex-1+array.length)%array.length];
}
}
public boolean isEmpty() {
return size==0;
}
public boolean isFull() {
return size==array.length;
}
}
总结
此处的概念并不复杂,尤其是栈。这种思想在我们进行递归分治的时候很有帮助。