题目:232. 用栈实现队列
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:
void push(int x):将元素x推到队列的末尾。int pop():从队列的开头移除并返回元素。int peek():返回队列开头的元素。boolean empty():如果队列为空,返回true;否则,返回false。
说明:
- 你只能使用标准的栈操作 —— 即
push to top、peek/pop from top、size和is empty操作。 - 你可以使用
list或deque模拟一个栈,只要是标准的栈操作即可。
解题思路
使用两个栈 stackIn 和 stackOut 来实现队列的 FIFO(先进先出)特性:
- push 操作:直接将元素压入
stackIn,保持stackIn中的顺序。 - pop 操作:当
stackOut为空时,将stackIn中的所有元素依次弹出并压入stackOut,此时stackOut的顶部元素即为队列的前端元素。然后从stackOut弹出元素即可。 - peek 操作:类似于
pop操作,首先将stackIn的元素移到stackOut,但此操作不移除元素,只返回队列前端的元素。 - empty 操作:当
stackIn和stackOut都为空时,队列为空。
反思
- 效率优化:原代码在
pop和peek操作中将stackIn的元素来回倒入stackOut,造成不必要的重复操作。优化后,stackOut只在为空时才从stackIn导入元素。 - 空间管理:双栈方案利用两个栈倒腾元素,使得队列保持 FIFO 特性。通过判断
stackOut是否为空,可以减少元素转移次数,提高效率。 - 易错点:需要注意
peek操作后不能将元素移除,否则会导致数据丢失。
class MyQueue {
Stack<Integer> stackIn;
Stack<Integer> stackOut;
public MyQueue() {
stackIn = new Stack<>();
stackOut = new Stack<>();
}
public void push(int x) {
stackIn.push(x);
}
public int pop() {
while(!stackIn.isEmpty()){
stackOut.push(stackIn.pop());
}
int temp = stackOut.pop();
while(!stackOut.isEmpty()){
stackIn.push(stackOut.pop());
}
return temp;
}
public int peek() {
while(!stackIn.isEmpty()){
stackOut.push(stackIn.pop());
}
int temp = stackOut.pop();
stackIn.push(temp);
while(!stackOut.isEmpty()){
stackIn.push(stackOut.pop());
}
return temp;
}
public boolean empty() {
return stackIn.isEmpty();
}
}
题目:225. 用队列实现栈
使用队列实现栈的下列操作:
push(x)– 将元素x入栈。pop()– 移除栈顶元素。top()– 获取栈顶元素。empty()– 返回栈是否为空。
解题思路
为了用队列实现栈的后进先出(LIFO)特性,我们可以使用两个队列来模拟栈的操作:
- push:将元素添加到主队列
queue中。 - pop:需要移除栈顶元素,而队列只能从队首移除元素,因此要将
queue中的前size-1个元素移到辅助队列helperQueue中,然后队列剩下的唯一元素即为栈顶元素,将其移除并返回。之后将辅助队列与主队列互换以保持状态。 - top:获取栈顶元素,逻辑与
pop类似,但不移除最后的元素。 - empty:检查主队列是否为空。
反思
- 效率优化:本代码实现了用一个队列来存储元素和一个辅助队列来处理“栈顶”元素的获取。通过在每次
pop或top操作时借助辅助队列,减少了重复操作。 - 空间管理:实现了队列的双重互换以模拟栈的 LIFO 行为。
- 边界条件:考虑栈为空时的情况,确保
pop和top在队列为空时能正确处理。
代码
class MyStack {
Deque<Integer> quene;
int size = 0;
public MyStack() {
quene = new ArrayDeque<>();
}
public void push(int x) {
size++;
quene.push(x);
}
public int pop() {
int temp = 0;
for(int i=0;i<size-1;i++){
temp = quene.pop();
quene.push(temp);
}
size--;
return quene.pop();
}
public int top() {
int temp = 0;
for(int i=0;i<size;i++){
temp = quene.pop();
quene.push(temp);
}
return temp;
}
public boolean empty() {
if(size>0){
return false;
}else {
return true;
}
}
}
class MyStack {
Queue<Integer> queue1; // 和栈中保持一样元素的队列
Queue<Integer> queue2; // 辅助队列
public MyStack() {
queue1 = new LinkedList<>();
queue2 = new LinkedList<>();
}
public void push(int x) {
queue2.offer(x);
while(!queue1.isEmpty()){
queue2.offer(queue1.poll());
}
Queue<Integer> queue3 = new LinkedList<>();
queue3 = queue1;
queue1 = queue2;
queue2 = queue3;
}
public int pop() {
return queue1.poll();
}
public int top() {
return queue1.peek();
}
public boolean empty() {
return queue1.isEmpty();
}
}
题目:20. 有效的括号
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
解题思路
本题的目标是判断括号是否有效配对。可以通过栈的后进先出特性来实现括号的有效匹配:
- 栈的使用:将所有左括号的对应右括号压入栈中。当遇到右括号时,检查栈顶元素是否是相匹配的右括号。
- 入栈和出栈规则:
- 遍历字符串中的每个字符,遇到左括号时将对应的右括号入栈。
- 遇到右括号时,检查栈是否为空以及栈顶元素是否匹配:
- 若栈为空或不匹配,则返回
false。 - 若匹配,则弹出栈顶元素继续匹配。
- 若栈为空或不匹配,则返回
- 结束检查:遍历结束后检查栈是否为空,如果栈为空说明所有括号均匹配,返回
true;否则返回false。
反思
- 栈的选择:虽然题目为用队列实现栈,但在这种场景下,栈更适合用来处理成对的符号检查,而队列则适合先进先出(FIFO)场景。
- 代码简化:可以在一轮遍历中完成括号匹配的检查,减少不必要的判断逻辑。
- 边界条件:对于空栈或多余的右括号情况,应提前返回
false以提高代码的健壮性。
代码
class Solution {
public boolean isValid(String s) {
Deque<Character> sb = new LinkedList<>();
for(int i=0;i<s.length();i++){
if(s.charAt(i)=='('){
sb.push(')');
} else if (s.charAt(i)=='{') {
sb.push('}');
} else if (s.charAt(i)=='[') {
sb.push(']');
}else if (s.charAt(i)==')' || s.charAt(i)=='}' || s.charAt(i)==']') {
if(!sb.isEmpty()){
if(s.charAt(i)==sb.peek()){
sb.pop();
}else {
return false;
}
}
else {
return false;
}
}
}
if(!sb.isEmpty()){
return false;
}else {
return true;
}
}
}
题目:1047. 删除字符串中的所有相邻重复项
给定一个由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。完成所有重复项删除操作后,返回最终的字符串。答案保证唯一。
解题思路
可以利用栈的特性来实现该操作的高效执行:
- 使用栈(或双指针法):遍历字符串中的每个字符,使用一个栈来存储字符。
- 遇到与栈顶相同的字符时,出栈,表示移除相邻的重复项。
- 遇到不同字符则入栈。
- 双指针实现:也可以使用双指针来优化空间,省去栈的空间开销。
- 用两个指针
fast和slow,fast指针遍历整个字符串,slow维护没有重复项的部分。 - 当
fast指向的字符与slow - 1相同时,指针slow回退;否则将字符放入slow位置。
- 用两个指针
反思
- 栈的使用:此题可以通过栈来实现,利用栈的后进先出特性方便处理相邻字符的重复问题。
- 双指针优化:使用双指针可以节省空间,因为仅需在原数组上直接操作,提高了效率。
- 边界情况:如空字符串、全部重复或无重复项的字符串,都需要确保代码能够正常处理。
代码
class Solution {
public String removeDuplicates(String s) {
StringBuffer res = new StringBuffer();
int right = 0;
for(int i=0;i<s.length();i++){
char c = s.charAt(i);
if(right == 0 || c!=res.charAt(right-1)){
res.append(c);
right++;
}else{
res.deleteCharAt(right-1);
right--;
}
}
return res.toString();
}
}
class Solution {
public String removeDuplicates(String s) {
char[] ch = s.toCharArray();
int fast = 0;
int slow = 0;
while(fast<s.length()){
ch[slow] = ch[fast];
if(slow>0 && ch[slow]==ch[slow-1]){
slow--;
}else {
slow++;
}
fast++;
}
return new String(ch,0,slow);
}
}

被折叠的 条评论
为什么被折叠?



