题目描述:
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
括号匹配OJ链接
代码示例:
class Solution {
public boolean isValid(String s) {
Stack<Character> st=new Stack<>();
//遍历字符串
for(int i=0;i<s.length();i++){
char c=s.charAt(i);
if(c == '('||c == '['||c == '{'){
//如果是左括号就入栈
st.push(c);
}else{
//如果是右括号就与栈顶元素比较,前提是栈不空,匹配的上就出栈
if(st.empty()){
return false;//此时栈空,无法匹配
}
//获取栈顶元素,与c来进行匹配
char pop=st.peek();
if((pop=='('&&c==')')||(pop=='['&&c==']')||(pop=='{'&&c=='}')){
st.pop();
continue;
}else{
return false;
}
}
}
//如果完全匹配,栈一定是空的,结果是true;
if(st.empty()){
return true;
}else{
return false;
}
}
}
逆波兰表达式又叫做后缀表达式。逆波兰表达式把运算量写在前面,把算符写在后面。
正常的表达式 | 逆波兰表达式 |
---|---|
a+b | a,b,+ |
a+(b-c) | a,b,c,-,+ |
a+(b-c)*d | a,d,b,c,-,*,+ |
a*(b+c)+d | a,b,c,+,*,d,+ |
有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
逆波兰表达式求值
代码示例:
import java.util.ArrayList;
import java.util.Stack;
class Solution {
public int evalRPN(String[] tokens) {
Stack<Integer> s=new Stack<>();
for(String e:tokens){
if(!((e.equals("+"))||(e.equals("-"))||
(e.equals("*"))||(e.equals("/")))){
//如果是数字,就入栈,需要把字符串转为数字类型再入栈
s.push(Integer.parseInt(e));
}else{
//如果是运算符,就从栈顶取出两个元素,进行运算,先取出的是右操作数、后取出的是左操作数
int right=s.pop();
int left=s.pop();
switch(e){
case "+":
s.push(left+right);
break;
case "-":
s.push(left-right);
break;
case "*":
s.push(left*right);
break;
case "/":
s.push(left/right);
break;
}
}
}
return s.peek();
}
}
题目描述:
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
栈的压入弹出序列OJ链接
代码示例:
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
public boolean IsPopOrder(int [] pushA,int [] popA) {
Stack<Integer> s = new Stack<>();
int inIndex = 0;
int outIndex = 0;
while (outIndex < popA.length) {
while (s.empty() || s.peek() != popA[outIndex]) {
if (inIndex < pushA.length) {
s.push(pushA[inIndex]);
inIndex++;
} else {
return false;
}
}
s.pop();
outIndex++;
}
return true;
}
}
用队列实现栈OJ链接
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
注意:
你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
代码示例:
class MyStack {
Queue<Integer> q1=new LinkedList<>();
Queue<Integer> q2=new LinkedList<>();
public MyStack() {
}
//入栈,哪个队列不空就往哪个里面放,保持其中一个队列为空
public void push(int x) {
if(q2.isEmpty()){
q1.offer(x);
}else{
q2.offer(x);
}
}
//出栈,哪个队列中有元素,就将哪个队列中的前n-1个元素搬移到另一个队列中,然后将此队列中的队头元素删除
public int pop() {
int ret=0;
if(!q1.isEmpty()){
//q1中有元素
while(q1.size()>1){
//把q1中的前n-1个元素放到q2中
q2.offer(q1.poll());
}
//此时q1中只剩下一个队头元素,也就是栈顶元素
ret=q1.poll();
}else{
//q2中有元素
while(q2.size()>1){
//把q2中的前n-1个元素放到q1中
q1.offer(q2.poll());
}
//此时q2中只剩下一个队头元素,也就是栈顶元素
ret=q2.poll();
}
return ret;
}
public int top() {
int ret=0;
if(!q1.isEmpty()){
//q1中有元素
while(q1.size()>1){
//把q1中的前n-1个元素放到q2中
q2.offer(q1.poll());
}
//此时q1中只剩下一个队头元素,也就是栈顶元素
ret=q1.peek();
q2.offer(q1.poll());
}else{
//q2中有元素
while(q2.size()>1){
//把q2中的前n-1个元素放到q1中
q1.offer(q2.poll());
}
//此时q2中只剩下一个队头元素,也就是栈顶元素
ret=q2.peek();
q1.offer(q2.poll());
}
return ret;
}
public boolean empty() {
return q1.isEmpty()&&q2.isEmpty();
}
}
用两个栈实现队列
class MyQueue {
Stack <Integer> s1=new Stack<>();//用s1模拟入队列
Stack <Integer> s2=new Stack<>();//用s2模拟出队列
public MyQueue() {
}
public void push(int x) {
s1.push(x);
}
public int pop() {
if(s2.empty()){
while(s1.size() >0){
s2.push(s1.pop());
}
}
return s2.pop();
}
public int peek() {
if(s2.empty()){
while(s1.size() >0){
s2.push(s1.pop());
}
}
return s2.peek();
}
public boolean empty() {
return s1.empty()&&s2.empty();
}
}
实现一个最下栈
class MinStack {
//用两个栈来实现
Stack<Integer> s1;//用s1来保存栈中的元素
Stack<Integer> s2;//用s2来保存最小元素
public MinStack() {
s1=new Stack<>();
s2=new Stack<>();
}
public void push(int val) {
//入栈,如果s2是空的,将元素往s1、s2各压入一份
if(s2.empty()){
s1.push(val);
s2.push(val);
}else if(val>s2.peek()){
//如果val>s2栈顶元素,就把val压入s1
s1.push(val);
}else{
//如果val<=s2栈顶元素,就把val往s1、s2各压入一份
s1.push(val);
s2.push(val);
}
}
public void pop() {
//出栈,如果s1和s2栈顶元素相同,则s1和s2同时出栈
//否则,只出栈s1
if(s1.peek().equals(s2.peek())){//包装类型,不能直接用==来比较
s1.pop();
s2.pop();
}else{
s1.pop();
}
}
public int top() {
return s1.peek();
}
public int getMin() {
return s2.peek();
}
}
设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
你的实现应该支持如下操作:
class MyCircularQueue {
int[] array;//用数组来存储元素
int front=0;//队头
int rear=0;//队尾
int count=0;
int N;
public MyCircularQueue(int k) {
array=new int[k];
N=k;
}
public boolean enQueue(int value) {
//向队列中插入元素
if(isFull()){
return false;
}
array[rear]=value;
rear++;
//如果存满了,要把rear重置为1;
if(rear==N){
rear=0;
}
count+=1;
return true;
}
public boolean deQueue() {
//出队列,从队头出
if(isEmpty()){
return false;
}
front++;
front%=N;
count-=1;
return true;
}
public int Front() {
if(isEmpty()){
return -1;
}
return array[front];
}
public int Rear() {
if(isEmpty()){
return -1;
}
return array[(rear-1+N)%N];
}
public boolean isEmpty() {
return count==0;
}
public boolean isFull() {
return count==N;
}
}