232.用栈实现队列
题目
使用栈实现队列的下列操作:
push(x) -- 将一个元素放入队列的尾部。
pop() -- 从队列首部移除元素。
peek() -- 返回队列首部的元素。
empty() -- 返回队列是否为空。
思路
首先要理解栈和队列的基本特性,
栈的操作:先进后出
队列操作:先进先出
由此能够看出,栈和队列的操作顺序刚好相反,由此可以想到用两个栈组合起来实现队列的操作。
具体实现步骤:
1.定义两个栈stack1,stack2,并分别初始化
2.入队操作就直接使用stack1入栈操作,仅是为了存储数据
3.peek()出队操作,这里要考虑几种情况:
3.1.stack2为空,stack1不为空,此时出队操作需要先将stack1中的元素全部弹出到stack2,然后返回stack2的栈顶元素即可。
3.2.stack2不为空,直接返回stack2栈顶元素。
4.pop()操作,与peek相似,所以直接调用peek(),然后再直接弹出stack2()栈顶元素。
5.判空,当stack1和stack2都为空时,队列为空。
代码实现
class MyQueue {
// stack1 入队栈,stack2 出队栈
// 入队实现:stack1入栈
// 出队实现:stack2出栈,如果为空则把stack1中的所有元素弹出压入stack2.
// 如果stack1&&stack2都为空,则整个队列为空
private Stack<Integer> stack1;
private Stack<Integer> stack2;
public MyQueue() {
stack1 = new Stack<>();
stack2 = new Stack<>();
}
public void push(int x) {
stack1.push(x);
}
public int pop() {
peek();
return stack2.pop();
}
public int peek() {
if(!stack1.empty()&&stack2.empty()){
while(!stack1.empty()){
stack2.push(stack1.pop());
}
}
return stack2.peek();
}
public boolean empty() {
if(stack1.empty()&&stack2.empty()){
return true;
}
return false;
}
}
225. 用队列实现栈
题目
使用队列实现栈的下列操作:
- push(x) -- 元素 x 入栈
- pop() -- 移除栈顶元素
- top() -- 获取栈顶元素
- empty() -- 返回栈是否为空
思路
解法一:双队列实现栈
用两个队列实现栈时,一个队列queue1用于存储,所有入栈都入queue1,另一个队列queue2用做备份。
入栈:直接存放进queue1,queue1.offer(x);
pop():1.获取queue1的元素数量记作size;
2.将queue1全部出队并备份到queue2中;
3.将queue2中的前size-1个元素出队并重新入队到queue1;
4.queue2中仅剩的一个元素就是需要的栈顶元素,将其弹出queue2.pop()并返回;
peek(): 与pop()操作仅第四步不一样,将queue2中的最后一个元素弹出并重新入队到queue1中,然后返回。
empty(): 当queue1为空时,栈为空。
代码实现
class MyStack {
private Queue<Integer> queue1;
private Queue<Integer> queue2;
public MyStack() {
queue1 = new LinkedList<>();
queue2 = new LinkedList<>();
}
public void push(int x) {
queue1.offer(x);
}
public int pop() {
while(!queue1.isEmpty()){
queue2.offer(queue1.poll());
}
int size = queue2.size();
for(int i=1;i<size;i++){
queue1.offer(queue2.poll());
}
int top = queue2.poll();
return top;
}
public int top() {
while(!queue1.isEmpty()){
queue2.offer(queue1.poll());
}
int size = queue2.size();
for(int i=1;i<size;i++){
queue1.offer(queue2.poll());
}
int top = queue2.poll();
queue1.offer(top);
return top;
}
public boolean empty() {
if(queue1.isEmpty()){
return true;
}
return false;
}
}
解法二:单队列实现栈
单个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时在去弹出元素就是栈的顺序了。
代码实现
class MyStack {
// Deque 接口继承了 Queue 接口
// 所以 Queue 中的 add、poll、peek等效于 Deque 中的 addLast、pollFirst、peekFirst
Deque<Integer> que1;
/** Initialize your data structure here. */
public MyStack() {
que1 = new ArrayDeque<>();
}
/** Push element x onto stack. */
public void push(int x) {
que1.addLast(x);
}
/** Removes the element on top of the stack and returns that element. */
public int pop() {
int size = que1.size();
size--;
while (size-- > 0) {
que1.addLast(que1.peekFirst());
que1.pollFirst();
}
int res = que1.pollFirst();
return res;
}
/** Get the top element. */
public int top() {
return que1.peekLast();
}
/** Returns whether the stack is empty. */
public boolean empty() {
return que1.isEmpty();
}
}
20. 有效的括号
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 注意空字符串可被认为是有效字符串。
示例 1:
- 输入: "()"
- 输出: true
思路
因为有效的字符括号都是成对的而且对称匹配,这种规律很适合使用栈来解决。
具体实现步骤:
首先定义一个栈,从左到右遍历字符串,遇到左括号压入栈。
遇到右括号,弹出栈顶元素判断是否是对应的左括号,如果不是返回false.
特殊情况处理:
1.如果只有左括号的情况,必然最后栈不为空,判断栈不为空就返回false.
2.如果只有右括号的情况,必然栈一直为空,在遇到右括号时,判断栈为空就返回false.
代码实现
class Solution {
public boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
for(int i=0;i<s.length();i++){
char c = s.charAt(i);
if(c=='('||c=='{'||c=='['){
stack.push(c);
}
if(c==')'){
if(stack.empty()){
return false;
}
char top = stack.pop();
if(top!='('){
return false;
}
}
if(c=='}'){
if(stack.empty()){
return false;
}
char top = stack.pop();
if(top!='{'){
return false;
}
}
if(c==']'){
if(stack.empty()){
return false;
}
char top = stack.pop();
if(top!='['){
return false;
}
}
}
if(!stack.empty()){
return false;
}
return true;
}
}
1047. 删除字符串中的所有相邻重复项
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
示例:
- 输入:"abbaca"
- 输出:"ca"
- 解释:例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。
思路
与括号匹配类似的解法,都可以利用栈的特性来解决。
代码实现
class Solution {
public String removeDuplicates(String s) {
Stack<Character> stack = new Stack<>();
for(int i=0;i<s.length();i++){
char c = s.charAt(i);
if(stack.empty()){
stack.push(c);
} else{
char top = stack.peek();
if(top==c){
stack.pop();
}else{
stack.push(c);
}
}
}
String str = "";
while(!stack.empty()){
char c = stack.pop();
str = c+str;
}
return str;
}
}
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;
}
}