232.用栈实现队列
使用栈实现队列的下列操作:
push(x) -- 将一个元素放入队列的尾部。
pop() -- 从队列首部移除元素。
peek() -- 返回队列首部的元素。
empty() -- 返回队列是否为空。
个人代码:(仅供参考,便于后期回顾)
class MyQueue {
//原来的栈存储元素
Stack<Integer> stack1;;
//辅助栈
Stack<Integer> stack2;
public MyQueue() {
//原来的栈存储元素
this.stack1=new Stack<>();
//辅助栈
this.stack2=new Stack<>();
}
public void push(int x) {
this.stack1.push(x);
}
public int pop() {
if(this.stack2.empty()){
while (!this.stack1.empty()){
int value=this.stack1.pop();
this.stack2.push(value);
}
}
return this.stack2.pop();
}
public int peek() {
if(this.stack2.empty()){
int value=this.pop();
this.stack2.push(value);
return value;
}
return this.stack2.peek();
}
public boolean empty() {
if(stack2.empty()&&stack1.empty()){
return true;
}else {
return false;
}
}
}
/**
* 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();
*/
总结:需要了解栈先进后出、队列先进先出的特点,并且在peek()的实现中,直接复用了pop(), 要不然,对stOut判空的逻辑又要重写一遍。进行peek操作复用pop()并不会提升时间的复杂度,之后重新push对应值即可。
225. 用队列实现栈
使用队列实现栈的下列操作:
- push(x) -- 元素 x 入栈
- pop() -- 移除栈顶元素
- top() -- 获取栈顶元素
- empty() -- 返回栈是否为空
注意:
- 你只能使用队列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty 这些操作是合法的。
- 你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
- 你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。
个人代码:(仅供参考,便于后期回顾)
class MyStack {
Queue<Integer> queue1;
// 辅助队列
Queue<Integer> queue2;
public MyStack() {
//初始化原队列1
queue1 = new LinkedList<Integer>();
//初始化辅助队列2
queue2 = new LinkedList<Integer>();
}
public void push(int x) {
//虚拟栈,直接入栈
queue1.offer(x);
}
public int pop() {
//由于虚拟栈是后进先出
int length = queue1.size();
length--;
//找到队列中的最后一个元素即为需要出栈的元素
while ((length--) > 0) {
int value = queue1.poll();
//先将队尾元素之前的全部元素插入辅助队列
queue2.offer(value);
}
//再将辅助队列的全部送入原先队列
while (!queue2.isEmpty()) {
int value2 = queue2.poll();
queue1.offer(value2);
}
//此时第一个元素即为出栈元素
return queue1.poll();
}
public int top() {
int value = this.pop();
this.push(value);
return value;
}
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();
*/
代码随想录参考代码:
class MyStack {
Queue<Integer> queue1; // 和栈中保持一样元素的队列
Queue<Integer> queue2; // 辅助队列
/** Initialize your data structure here. */
public MyStack() {
queue1 = new LinkedList<>();
queue2 = new LinkedList<>();
}
/** Push element x onto stack. */
public void push(int x) {
queue2.offer(x); // 先放在辅助队列中
while (!queue1.isEmpty()){
queue2.offer(queue1.poll());
}
Queue<Integer> queueTemp;
queueTemp = queue1;
queue1 = queue2;
queue2 = queueTemp; // 最后交换queue1和queue2,将元素都放到queue1中
}
/** Removes the element on top of the stack and returns that element. */
public int pop() {
return queue1.poll(); // 因为queue1中的元素和栈中的保持一致,所以这个和下面两个的操作只看queue1即可
}
/** Get the top element. */
public int top() {
return queue1.peek();
}
/** Returns whether the stack is empty. */
public boolean empty() {
return queue1.isEmpty();
}
}
20. 有效的括号
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 注意空字符串可被认为是有效字符串。
示例 1:
- 输入: "()"
- 输出: true
示例 2:
- 输入: "()[]{}"
- 输出: true
示例 3:
- 输入: "(]"
- 输出: false
示例 4:
- 输入: "([)]"
- 输出: false
示例 5:
- 输入: "{[]}"
- 输出: true
个人代码:(仅供参考,便于后期回顾)
class Solution {
public boolean isValid(String s) {
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()||stack.peek()!=s.charAt(i)){
return false;
}else {
stack.pop();
}
}
return stack.isEmpty();
}
}
代码随想录参考代码:
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. 删除字符串中的所有相邻重复项
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
示例:
- 输入:"abbaca"
- 输出:"ca"
- 解释:例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。
提示:
- 1 <= S.length <= 20000
- S 仅由小写英文字母组成。
个人代码:(仅供参考,便于后期回顾)
class Solution {
public String removeDuplicates(String s) {
Deque<Character> dequelist = new LinkedList<>();
for (int i = 0; i < s.length(); i++) {
if (dequelist.isEmpty()) {
dequelist.push(s.charAt(i));
continue;
}
if (s.charAt(i) == dequelist.peek()) {
dequelist.pop();
} else {
dequelist.push(s.charAt(i));
}
}
String result = "";
while (!dequelist.isEmpty()) {
result = result + dequelist.pollLast();
}
return result;
}
}
代码随想录参考代码:
class Solution {
public String removeDuplicates(String S) {
//ArrayDeque会比LinkedList在除了删除元素这一点外会快一点
//参考:https://stackoverflow.com/questions/6163166/why-is-arraydeque-better-than-linkedlist
ArrayDeque<Character> deque = new ArrayDeque<>();
char ch;
for (int i = 0; i < S.length(); i++) {
ch = S.charAt(i);
if (deque.isEmpty() || deque.peek() != ch) {
deque.push(ch);
} else {
deque.pop();
}
}
String str = "";
//剩余的元素即为不重复的元素
while (!deque.isEmpty()) {
str = deque.pop() + str;
}
return str;
}
}
总结:此题是匹配相邻元素,其实都是做消除的操作,想到消除那就能想到栈的括号匹配,因此此题也是用栈来解决的经典题目。