232.用栈实现队列
思路:利用一个栈作为辅助,在存入元素的时候调整元素的顺序,使得取出元素时符合先进先出。
class MyQueue {
private Stack<Integer> st1;
private Stack<Integer> st2; // 辅助栈
public MyQueue() {
st1 = new Stack<>();
st2 = new Stack<>();
}
public void push(int x) {
if (st1.empty()) {
st1.push(x);
} else {
while (!st1.empty()) {
st2.push(st1.pop());
}
st1.push(x);
while (!st2.empty()) {
st1.push(st2.pop());
}
}
}
public int pop() {
return st1.pop();
}
public int peek() {
return st1.peek();
}
public boolean empty() {
return st1.empty();
}
}
随想录中思路:一个栈作为输入栈,一个栈作为输出栈。在push数据的时候,直接将数据放到输入栈,在pop数据的时候,如果输出栈为空,将输入栈的数据全部导入到输出栈,如果输出栈不为空,直接pop输出栈。如果两个栈都为空,模拟队列为空。
class MyQueue {
private Stack<Integer> stackIn;
private Stack<Integer> stackOut;
public MyQueue() {
stackIn = new Stack<>();
stackOut = new Stack<>();
}
public void push(int x) {
stackIn.push(x);
}
public int pop() {
if (stackOut.empty()) {
while (!stackIn.empty()) {
stackOut.push(stackIn.pop());
}
}
return stackOut.pop();
}
public int peek() {
if (stackOut.empty()) {
while (!stackIn.empty()) {
stackOut.push(stackIn.pop());
}
}
return stackOut.peek();
}
public boolean empty() {
return stackIn.empty() && stackOut.empty();
}
}
225. 用队列实现栈
思路:利用一个队列作为辅助,在存入元素的时候调整元素的顺序,使得取出元素时符合先进后出。
class MyStack {
private Queue<Integer> queue1;
private Queue<Integer> queue2; // 辅助队列
public MyStack() {
queue1 = new LinkedList<>();
queue2 = new LinkedList<>();
}
public void push(int x) {
if (queue1.peek() == null) {
queue1.offer(x);
} else {
while (queue1.peek() != null) {
queue2.offer(queue1.poll());
}
queue1.offer(x);
while (queue2.peek() != null) {
queue1.offer(queue2.poll());
}
}
}
public int pop() {
return queue1.poll();
}
public int top() {
return queue1.peek();
}
public boolean empty() {
return queue1.peek() == null;
}
}
随想录中思路:一个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时再去弹出元素就是栈的顺序了。
class MyStack {
// Deque 接口继承了 Queue 接口
// 所以 Queue 中的 add、poll、peek等效于 Deque 中的 addLast、pollFirst、peekFirst
Deque<Integer> que1;
public MyStack() {
que1 = new ArrayDeque<>();
}
public void push(int x) {
que1.addLast(x);
}
public int pop() {
int size = que1.size() - 1;
// 将 que1 导入 que2 ,但留下最后一个值
while (size-- > 0) {
que1.addLast(que1.pollFirst(););
}
return rque1.pollFirst();
}
public int top() {
return que1.peekLast();
}
public boolean empty() {
return que1.isEmpty();
}
}
20. 有效的括号
思路:利用栈,当栈为空时,遍历的元素压入栈中。当遇到右括号时,如果栈中的元素和遍历的元素匹配,则弹栈,否则将元素压入栈中。最后遍历结束,如果栈为空,那么说明所有的括号匹配成功。
时间复杂度O(n)
class Solution {
public boolean isValid(String s) {
char[] ch = s.toCharArray();
Stack<Character> stack = new Stack<>();
for (int i = 0; i < ch.length; i++) {
if (stack.empty()) {
stack.push(ch[i]);
} else if (ch[i] == ')' && stack.peek() == '(') {
stack.pop();
} else if (ch[i] == ']' && stack.peek() == '[') {
stack.pop();
} else if (ch[i] == '}' && stack.peek() == '{') {
stack.pop();
} else {
stack.push(ch[i]);
}
}
if (stack.empty()) return true;
return false;
}
}
随想录中的思路:一次遍历,遇到左括号,就把相应的右括号push栈中。遇到右括号,查看是否和栈中元素相同,相同弹栈,不同返回false。遍历结束后栈为空,说明匹配成功。
class Solution {
public boolean isValid(String s) {
Deque<Character> stack = new LinkedList<>();
char[] ch = s.toCharArray();
for (int i = 0; i < ch.length; i++) {
if (ch[i] == '(') {
stack.push(')');
} else if (ch[i] == '[') {
stack.push(']');
} else if (ch[i] == '{') {
stack.push('}');
} else if (stack.isEmpty() || stack.peek() != ch[i]) {
return false;
} else {
stack.pop();
}
}
if (stack.isEmpty()) return true;
return false;
}
}
1047. 删除字符串中的所有相邻重复项
思路:为什么会想到用栈?因为和上一题有效括号一样,都是做消除操作。匹配问题时栈的强项。栈为什么适合做这种类似于爱消除的操作,因为栈帮助我们记录了遍历数组当前元素时候,前一个元素是什么。
时间复杂度O(n)
class Solution {
public String removeDuplicates(String s) {
// 栈为什么适合做这种类似于爱消除的操作,
// 因为栈帮助我们记录了 遍历数组当前元素时候,前一个元素是什么。
char[] ch = s.toCharArray();
Stack<Character> stack = new Stack<>();
for (int i = 0; i < ch.length; i++) {
if (stack.empty()) {
stack.push(ch[i]);
} else if (ch[i] == stack.peek()) { // 如果当前元素等于栈顶元素
stack.pop();
} else {
stack.push(ch[i]);
}
}
StringBuilder sb = new StringBuilder();
while (!stack.empty()) {
sb.insert(0,stack.pop());
}
return sb.toString();
}
}
与随想录中思路相同。注意事项:ArrayDeque会比LinkedList在除了删除元素这一点外会快一点。详情参考链接。