跳转:232. 用栈实现队列
问题:
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push
、pop
、peek
、empty
):
实现 MyQueue
类:
void push(int x)
将元素 x 推到队列的末尾int pop()
从队列的开头移除并返回元素int peek()
返回队列开头的元素boolean empty()
如果队列为空,返回 true
;否则,返回 false
思路:
说是只用栈,先进后出后进,就可以先出(相当于翻转栈)
所以需要两个栈,需要取值时将值倒到另一个栈取出
由于另一个栈的出栈顺序就是先进先出,所以可以保持原样而无需倒回,等取空再倒
复杂度:
代码(批量倾倒):
class MyQueue {
Stack<Integer> in;
Stack<Integer> out;
public MyQueue() {
in = new Stack<>();
out = new Stack<>();
}
public void push(int x) {
in.push(x);
}
private void inToOut(){
if(!out.isEmpty()) return;
while(!in.isEmpty()) {
out.push(in.pop());
}
}
public int pop() {
inToOut();
return out.pop();
}
public int peek() {
inToOut();
return out.peek();
}
public boolean empty() {
return in.isEmpty()&&out.isEmpty();
}
}
复杂度:
代码(每步恢复栈):
class MyQueue {
Stack<Integer> in;
Stack<Integer> out;
public MyQueue() {
in = new Stack<>();
out = new Stack<>();
}
public void push(int x) {
in.push(x);
}
private void inToOut(){
while(!in.isEmpty()) {
out.push(in.pop());
}
}
private void outToIn(){
while(!out.isEmpty()) {
in.push(out.pop());
}
}
public int pop() {
inToOut();
int n = out.pop();
outToIn();
return n;
}
public int peek() {
inToOut();
int n = out.pop();
in.push(n);
outToIn();
return n;
}
public boolean empty() {
return in.isEmpty();
}
}
跳转: 225. 用队列实现栈
问题:
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push
、top
、pop
和 empty
)。
实现 MyStack
类:
void push(int x)
将元素 x 压入栈顶。int pop()
移除并返回栈顶元素。int top()
返回栈顶元素。boolean empty()
如果栈是空的,返回 true
;否则,返回 false
。思路:
先进先出先进,所以倒到另一个队列中会保持顺序
这里只能用笨方法,就是倒出留最后一个末尾
但是可以加一步优化,就是将自己的头倒到自身尾部,可以看作是一个循环的过程.
复杂度:
代码(单队列循环):
class MyStack {
private Queue<Integer> queue;
public MyStack() {
queue = new LinkedList<>();
}
public void push(int x) {
queue.add(x);
}
private void dump() {
int len = queue.size();
while(--len>0) {
queue.add(queue.poll());
}
}
public int pop() {
dump();
return queue.poll();
}
public int top() {
dump();
int n = queue.poll();
queue.add(n);
return n;
}
public boolean empty() {
return queue.isEmpty();
}
}
代码(双队列轮换):
class MyStack {
private Queue<Integer> queueA;
private Queue<Integer> queueB;
public MyStack() {
queueA = new LinkedList<>();
queueB = new LinkedList<>();
}
public void push(int x) {
if(queueB.isEmpty()) queueA.add(x);
else queueB.add(x);
}
private int dump() {
if(queueA.isEmpty()) {
while(queueB.size()>1) {
queueA.add(queueB.poll());
}
return 0;
}else {
while(queueA.size()>1) {
queueB.add(queueA.poll());
}
return 1;
}
}
public int pop() {
if(dump()==1) {
return queueA.poll();
}
else {
return queueB.poll();
}
}
public int top() {
if(dump()==1) {
int n = queueA.poll();
queueB.add(n);
return n;
}
else {
int n = queueB.poll();
queueA.add(n);
return n;
}
}
public boolean empty() {
return queueA.isEmpty()&&queueB.isEmpty();
}
}
跳转: 20. 有效的括号
问题:
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判断字符串是否有效。
有效字符串需满足:
思路:
有效情况指左右括号可以不跨过未配对的括号一一配对(不能有孤立的情况)
所以用栈对右括号三种配对情况做分组判断即可
复杂度:
代码:
class Solution {
public boolean isValid(String s) {
Stack<Character> st = new Stack<>();
for (int i = 0; i < s.length(); i++) {
char a = s.charAt(i);
switch (a) {
case ')':
if (st.isEmpty() || st.pop() != '(')
return false;
break;
case '}':
if (st.isEmpty() || st.pop() != '{')
return false;
break;
case ']':
if (st.isEmpty() || st.pop() != '[')
return false;
break;
default:
st.add(a);
}
}
return st.isEmpty();
}
}
跳转: 1047. 删除字符串中的所有相邻重复项
问题:
给出由小写字母组成的字符串 s
,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 s
上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
思路:
邻接配对相消,能看出用栈
可以直接用栈做最后再翻转成字符串
也可以直接原地(C语言可以直接操作字符串)
用慢指针模拟栈,最后取子数组
复杂度:
代码(双指针原地模拟栈):
class Solution {
public String removeDuplicates(String s) {
char[] ch = s.toCharArray();
int slow=0;
for(int i=1;i<ch.length;i++){
if(slow>-1&&ch[slow]==ch[i]){
slow--;
}else{
ch[++slow] = ch[i];
}
}
return new String(ch,0,slow+1);
}
}
代码(直接用栈):
class Solution {
public String removeDuplicates(String s) {
char[] ch = s.toCharArray();
int slow=0;
for(int i=1;i<ch.length;i++){
if(slow>-1&&ch[slow]==ch[i]){
slow--;
}else{
ch[++slow] = ch[i];
}
}
return new String(ch,0,slow+1);
}
}
跳转: 1123. 最深叶节点的最近公共祖先
问题:
给你一个有根节点 root
的二叉树,返回它 最深的叶节点的最近公共祖先 。
回想一下:
0
,如果某一节点的深度为 d
,那它的子节点的深度就是 d+1
A
是一组节点 S
的 最近公共祖先,S
中的每个节点都在以 A
为根节点的子树中,且 A
的深度达到此条件下可能的最大值。思路:
左子树深度等于右子树,才说明本节点是当前树叶节点的最近公共祖先
本题需要找所有最深叶子节点的公共祖先,所以只需要记录最深时最上方的最近公共祖先即可.
复杂度:
代码:
class Solution {
private int max = 0;
private TreeNode res;
public TreeNode lcaDeepestLeaves(TreeNode root) {
handle(root, 0);
return res;
}
private int handle(TreeNode root,int curDeep) {
if(root==null) return curDeep;
int a = handle(root.left, curDeep+1);
int b = handle(root.right, curDeep+1);
if(a==b) {
if(max<=a) {
max = a;
res = root;
}
}
return Math.max(a,b);
}
}
练习了栈和队列的基本操作push pop top
与add poll peek
练习了模拟栈和dfs
代码随想录算法训练营第一天
代码随想录算法训练营第二天
代码随想录算法训练营第三天
代码随想录算法训练营第四天
代码随想录算法训练营周末一
代码随想录算法训练营第五天
代码随想录算法训练营第六天
代码随想录算法训练营第七天
代码随想录算法训练营第八天