232.用栈实现队列
Java中栈的函数:
Stack<Integer> s = new Stack<>();
//判断栈是否为空
boolean isEmpty()
//返回栈中元素的个数
int size()
//压入元素
E push(E item)
//返回栈顶元素
E peek()
//删除并返回栈顶元素
E pop()
my solution:
class MyQueue {
Stack<Integer> inStack;
Stack<Integer> outStack;
public MyQueue() {
inStack = new Stack<>();// 负责进栈
outStack = new Stack<>();// 负责出栈
}
//元素入栈
public void push(int x) {
//说明没有元素,那直接入栈即可
if(inStack.isEmpty() && outStack.isEmpty()){
inStack.push(x);
//如果出栈中有元素,将其还原到入栈处
}else if(!outStack.isEmpty()){
while(!outStack.isEmpty()){
inStack.push(outStack.pop());
}
inStack.push(x);
}else if(!inStack.isEmpty()){
inStack.push(x);
}
}
//移除元素
public int pop() {
//不同
if(!inStack.isEmpty()){
while(!inStack.isEmpty()){
outStack.push(inStack.pop());
}
}
return outStack.pop();
}
public int peek() {
//不同
if(!inStack.isEmpty()){
while(!inStack.isEmpty()){
outStack.push(inStack.pop());
}
}
return outStack.peek();
}
public boolean empty() {
if(inStack.isEmpty() && outStack.isEmpty()){
return true;
}
return false;
}
}
有两个方向。
代码随想录:
class MyQueue {
Stack<Integer> stackIn;
Stack<Integer> stackOut;
/** Initialize your data structure here. */
public MyQueue() {
stackIn = new Stack<>(); // 负责进栈
stackOut = new Stack<>(); // 负责出栈
}
/** Push element x to the back of queue. */
public void push(int x) {
stackIn.push(x);
}
/** Removes the element from in front of queue and returns that element. */
public int pop() {
dumpstackIn();
return stackOut.pop();
}
/** Get the front element. */
public int peek() {
dumpstackIn();
return stackOut.peek();
}
/** Returns whether the queue is empty. */
public boolean empty() {
return stackIn.isEmpty() && stackOut.isEmpty();
}
// 如果stackOut为空,那么将stackIn中的元素全部放到stackOut中
private void dumpstackIn(){
if (!stackOut.isEmpty()) return;
while (!stackIn.isEmpty()){
stackOut.push(stackIn.pop());
}
}
}
只有一个方向:将元素从入栈移动到出栈。
225.用队列实现栈
注意是单向队列。
Java中队列的函数:
Queue<String> queue = new LinkedList<>();
//判断队列是否为空
boolean isEmpty()
//返回队列中元素的个数
int size()
//返回队头的元素
E peek()
//删除并返回队头的元素
E poll()
//将元素e插入队尾
boolean offer(E e)
用LinkedList来实现:
动的是入队列。
两个队列实现栈:
class MyStack {
Queue<Integer> queue1;
Queue<Integer> queue2;
public MyStack() {
queue1 = new LinkedList<Integer>();
queue2 = new LinkedList<Integer>();
}
//形成倒序
public void push(int x) {
//将x先加入到queue2中
queue2.offer(x);
//将queue1中的数据依次加入到queue2中
while (!queue1.isEmpty()) {
queue2.offer(queue1.poll());
}
//此时x是queue2中的第一个元素
Queue<Integer> temp = queue1;
queue1 = queue2;
queue2 = temp;
}
public int pop() {
return queue1.poll();
}
public int top() {
return queue1.peek();
}
public boolean empty() {
return queue1.isEmpty();
}
}
一个队列实现栈:
class MyStack {
Queue<Integer> queue;
public MyStack() {
queue = new LinkedList<>();
}
//每 offer 一个数(A)进来,都重新排列,把这个数(A)放到队列的队首
public void push(int x) {
queue.offer(x);
int size = queue.size();
//移动除了 A 的其它数
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();
}
}
用Deque来实现:
动的是出队列。
public void push(int x) {
que1.addLast(x);
}
public int pop() {
int size = que1.size();
size--;
// 将 que1 导入 que2 ,但留下最后一个值
while (size-- > 0) {
que2.addLast(que1.peekFirst());
que1.pollFirst();
}
int res = que1.pollFirst();
// 将 que2 对象的引用赋给了 que1 ,此时 que1,que2 指向同一个队列
que1 = que2;
// 如果直接操作 que2,que1 也会受到影响,所以为 que2 分配一个新的空间
que2 = new ArrayDeque<>();
return res;
}
public int top() {
return que1.peekLast();
}
public void push(int x) {
que1.addLast(x);
}
public int pop() {
int size = que1.size();
size--;
// 将 que1 导入 que2 ,但留下最后一个值
while (size-- > 0) {
que1.addLast(que1.peekFirst());
que1.pollFirst();
}
int res = que1.pollFirst();
return res;
}
public int top() {
return que1.peekLast();
}
20.有效的括号
用栈来实现。
不匹配的情况:
第一种情况:已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false
第二种情况:遍历字符串匹配的过程中,发现栈里没有要匹配的字符。所以return false
第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号return false
那么什么时候说明左括号和右括号全都匹配了呢,就是字符串遍历完之后,栈是空的,就说明全都匹配了。
如果是左括号,就压入对应的右括号。如果是右括号,则弹出栈顶元素与其进行匹配。
class Solution {
public boolean isValid(String s) {
if(s.length()%2 != 0){
return false;
}
Stack<Character> stack = new Stack<>();
for(int i=0;i<s.length();i++){
if(s.charAt(i) == '('){
stack.push(')');
}else if(s.charAt(i) == '['){
stack.push(']');
}else if(s.charAt(i) == '{'){
stack.push('}');
}else if(stack.isEmpty() || s.charAt(i)!=stack.peek()){
return false;
}else{//右括号与栈顶元素匹配
stack.pop();
}
}
return stack.isEmpty();//如果最后栈为空,则为true
}
}
LinkedList也是Deque的一种实现。
class Solution {
public boolean isValid(String s) {
Deque<Character> deque = new LinkedList<>();
char ch;
for (int i = 0; i < s.length(); i++) {
ch = s.charAt(i);
//碰到左括号,就把相应的右括号入栈
if (ch == '(') {
deque.push(')');
}else if (ch == '{') {
deque.push('}');
}else if (ch == '[') {
deque.push(']');
} else if (deque.isEmpty() || deque.peek() != ch) {
return false;
}else {//如果是右括号判断是否和栈顶元素匹配
deque.pop();
}
}
//最后判断栈中元素是否匹配
return deque.isEmpty();
}
}
1047.删除字符串中所有相邻重复项
class Solution {
public String removeDuplicates(String s) {
//双端队列
Deque<Character> deque = new LinkedList<>();
for(int i=0;i<s.length();i++){
if(deque.isEmpty()){
deque.addLast(s.charAt(i));
continue;
}
//只能碰掉一个,所以用if,而不是while
if(!deque.isEmpty() && deque.peekLast() == s.charAt(i)){
deque.pollLast();
}else{
deque.addLast(s.charAt(i));
}
}
StringBuilder sb = new StringBuilder();
while(!deque.isEmpty()){
sb.append(deque.pollFirst());
}
return new String(sb);
}
}
class Solution {
public String removeDuplicates(String s) {
// 将 res 当做栈
// 也可以用 StringBuilder 来修改字符串,速度更快
// StringBuilder res = new StringBuilder();
StringBuffer res = new StringBuffer();
// top为 res 的长度
int top = -1;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
// 当 top > 0,即栈中有字符时,当前字符如果和栈中字符相等,弹出栈顶字符,同时 top--
if (top >= 0 && res.charAt(top) == c) {
res.deleteCharAt(top);
top--;
// 否则,将该字符 入栈,同时top++
} else {
res.append(c);
top++;
}
}
return res.toString();
}
}
双指针:
class Solution {
public String removeDuplicates(String s) {
char[] ch = s.toCharArray();
int fast = 0;
int slow = 0;
while(fast < s.length()){
// 直接用fast指针覆盖slow指针的值
ch[slow] = ch[fast];
// 遇到前后相同值的,就跳过,即slow指针后退一步,下次循环就可以直接被覆盖掉了
if(slow > 0 && ch[slow] == ch[slow - 1]){
slow--;
}else{
slow++;
}
fast++;
}
return new String(ch,0,slow);
}
}
150.逆波兰表达式求值
与5差不多,只不过本题不是相邻元素做消除了,而是做运算。
先弹出来的是右操作数。
class Solution {
public int evalRPN(String[] tokens) {
Stack<Integer> stack = new Stack<>();
//先弹出来的是右操作数
for(int i=0;i<tokens.length;i++){
if ("+".equals(tokens[i])) {
stack.push(stack.pop() + stack.pop());
} else if ("-".equals(tokens[i])) {
stack.push(-stack.pop() + stack.pop());
} else if ("*".equals(tokens[i])) {
stack.push(stack.pop() * stack.pop());
} else if ("/".equals(tokens[i])) {
int temp1 = stack.pop();
int temp2 = stack.pop();
stack.push(temp2 / temp1);
} else {
stack.push(Integer.valueOf(tokens[i]));
}
}
return stack.pop();
}
}