From 9391bf2d12de419b39b28e5ca1ad01987af3f725 Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Wed, 3 Apr 2024 12:10:54 +0800 Subject: [PATCH] feat: add solutions to lcci problems: No.03.03,03.04 (#2532) --- lcci/03.03.Stack of Plates/README.md | 20 +- lcci/03.03.Stack of Plates/README_EN.md | 22 +- lcci/03.03.Stack of Plates/Solution.cpp | 12 +- .../README.md | 266 ++++++++++++------ .../README_EN.md | 266 ++++++++++++------ .../Solution.cpp | 47 ++++ .../Solution.go | 43 ++- .../Solution.java | 39 ++- .../Solution.py | 39 +-- .../Solution.rs | 48 ++++ .../Solution.ts | 32 +-- .../README.md | 41 ++- .../README_EN.md | 53 ++-- .../Solution.rs | 41 ++- 14 files changed, 604 insertions(+), 365 deletions(-) create mode 100644 lcci/03.04.Implement Queue using Stacks/Solution.cpp create mode 100644 lcci/03.04.Implement Queue using Stacks/Solution.rs diff --git a/lcci/03.03.Stack of Plates/README.md b/lcci/03.03.Stack of Plates/README.md index f51a85641164d..637bd3f17986f 100644 --- a/lcci/03.03.Stack of Plates/README.md +++ b/lcci/03.03.Stack of Plates/README.md @@ -26,7 +26,13 @@ ### 方法一:模拟 -用列表模拟栈的集合,每个栈的容量为 `cap`,当栈满时,新建一个栈。 +我们可以使用一个栈列表 $stk$ 来模拟这个过程,初始时 $stk$ 为空。 + +- 当调用 $push$ 方法时,如果 $cap$ 为 0,直接返回。否则,如果 $stk$ 为空或者 $stk$ 的最后一个栈的长度大于等于 $cap$,则新建一个栈。然后将元素 $val$ 加入到 $stk$ 的最后一个栈中。时间复杂度为 $O(1)$。 +- 当调用 $pop$ 方法时,返回 $popAt(|stk| - 1)$ 的结果。时间复杂度 $O(1)$。 +- 当调用 $popAt$ 方法时,如果 $index$ 不在 $[0, |stk|)$ 范围内,返回 -1。否则,返回 $stk[index]$ 的栈顶元素,并将其弹出。如果弹出后 $stk[index]$ 为空,将其从 $stk$ 中删除。时间复杂度 $O(1)$。 + +空间复杂度为 $O(n)$,其中 $n$ 为元素个数。 @@ -114,9 +120,13 @@ public: } void push(int val) { - if (!cap) return; - if (stk.empty() || stk[stk.size() - 1].size() >= cap) stk.emplace_back(stack()); - stk[stk.size() - 1].push(val); + if (!cap) { + return; + } + if (stk.empty() || stk.back().size() >= cap) { + stk.emplace_back(stack()); + } + stk.back().push(val); } int pop() { @@ -136,8 +146,8 @@ public: } private: - vector> stk; int cap; + vector> stk; }; /** diff --git a/lcci/03.03.Stack of Plates/README_EN.md b/lcci/03.03.Stack of Plates/README_EN.md index 55c1ba2995069..eaa9e0eabdc1d 100644 --- a/lcci/03.03.Stack of Plates/README_EN.md +++ b/lcci/03.03.Stack of Plates/README_EN.md @@ -39,7 +39,15 @@ ## Solutions -### Solution 1 +### Solution 1: Simulation + +We can use a list of stacks $stk$ to simulate this process, initially $stk$ is empty. + +- When the `push` method is called, if $cap$ is 0, return directly. Otherwise, if $stk$ is empty or the length of the last stack in $stk$ is greater than or equal to $cap$, then create a new stack. Then add the element $val$ to the last stack in $stk$. The time complexity is $O(1)$. +- When the `pop` method is called, return the result of `popAt(|stk| - 1)`. The time complexity is $O(1)$. +- When the `popAt` method is called, if $index$ is not in the range $[0, |stk|)$, return -1. Otherwise, return the top element of $stk[index]$ and pop it out. If $stk[index]$ is empty after popping, remove it from $stk$. The time complexity is $O(1)$. + +The space complexity is $O(n)$, where $n$ is the number of elements. @@ -127,9 +135,13 @@ public: } void push(int val) { - if (!cap) return; - if (stk.empty() || stk[stk.size() - 1].size() >= cap) stk.emplace_back(stack()); - stk[stk.size() - 1].push(val); + if (!cap) { + return; + } + if (stk.empty() || stk.back().size() >= cap) { + stk.emplace_back(stack()); + } + stk.back().push(val); } int pop() { @@ -149,8 +161,8 @@ public: } private: - vector> stk; int cap; + vector> stk; }; /** diff --git a/lcci/03.03.Stack of Plates/Solution.cpp b/lcci/03.03.Stack of Plates/Solution.cpp index 4c922b80ad4b8..48ae9ebf52a8a 100644 --- a/lcci/03.03.Stack of Plates/Solution.cpp +++ b/lcci/03.03.Stack of Plates/Solution.cpp @@ -5,9 +5,13 @@ class StackOfPlates { } void push(int val) { - if (!cap) return; - if (stk.empty() || stk[stk.size() - 1].size() >= cap) stk.emplace_back(stack()); - stk[stk.size() - 1].push(val); + if (!cap) { + return; + } + if (stk.empty() || stk.back().size() >= cap) { + stk.emplace_back(stack()); + } + stk.back().push(val); } int pop() { @@ -27,8 +31,8 @@ class StackOfPlates { } private: - vector> stk; int cap; + vector> stk; }; /** diff --git a/lcci/03.04.Implement Queue using Stacks/README.md b/lcci/03.04.Implement Queue using Stacks/README.md index 18f76c3c9be14..b20d26f7adcf1 100644 --- a/lcci/03.04.Implement Queue using Stacks/README.md +++ b/lcci/03.04.Implement Queue using Stacks/README.md @@ -9,47 +9,44 @@ ## 解法 -### 方法一 +### 方法一:双栈 + +我们使用两个栈,其中栈 `stk1`用于入队,另一个栈 `stk2` 用于出队。 + +入队时,直接将元素入栈 `stk1`。时间复杂度 $O(1)$。 + +出队时,先判断栈 `stk2` 是否为空,如果为空,则将栈 `stk1` 中的元素全部出栈并入栈 `stk2`,然后再从栈 `stk2` 中出栈一个元素。如果栈 `stk2` 不为空,则直接从栈 `stk2` 中出栈一个元素。均摊时间复杂度 $O(1)$。 + +获取队首元素时,先判断栈 `stk2` 是否为空,如果为空,则将栈 `stk1` 中的元素全部出栈并入栈 `stk2`,然后再从栈 `stk2` 中获取栈顶元素。如果栈 `stk2` 不为空,则直接从栈 `stk2` 中获取栈顶元素。均摊时间复杂度 $O(1)$。 + +判断队列是否为空时,只要判断两个栈是否都为空即可。时间复杂度 $O(1)$。 ```python class MyQueue: def __init__(self): - """ - Initialize your data structure here. - """ - self._s1, self._s2 = [], [] + self.stk1 = [] + self.stk2 = [] def push(self, x: int) -> None: - """ - Push element x to the back of queue. - """ - self._s1.append(x) + self.stk1.append(x) def pop(self) -> int: - """ - Removes the element from in front of queue and returns that element. - """ - if len(self._s2) == 0: - while self._s1: - self._s2.append(self._s1.pop()) - return self._s2.pop() + self.move() + return self.stk2.pop() def peek(self) -> int: - """ - Get the front element. - """ - if len(self._s2) == 0: - while self._s1: - self._s2.append(self._s1.pop()) - return self._s2[-1] + self.move() + return self.stk2[-1] def empty(self) -> bool: - """ - Returns whether the queue is empty. - """ - return len(self._s1) + len(self._s2) == 0 + return not self.stk1 and not self.stk2 + + def move(self): + if not self.stk2: + while self.stk1: + self.stk2.append(self.stk1.pop()) # Your MyQueue object will be instantiated and called as such: @@ -62,43 +59,36 @@ class MyQueue: ```java class MyQueue { - private Stack s1; - private Stack s2; + private Deque stk1 = new ArrayDeque<>(); + private Deque stk2 = new ArrayDeque<>(); - /** Initialize your data structure here. */ public MyQueue() { - s1 = new Stack<>(); - s2 = new Stack<>(); } - /** Push element x to the back of queue. */ public void push(int x) { - s1.push(x); + stk1.push(x); } - /** Removes the element from in front of queue and returns that element. */ public int pop() { - if (s2.empty()) { - while (!s1.empty()) { - s2.push(s1.pop()); - } - } - return s2.pop(); + move(); + return stk2.pop(); } - /** Get the front element. */ public int peek() { - if (s2.empty()) { - while (!s1.empty()) { - s2.push(s1.pop()); - } - } - return s2.peek(); + move(); + return stk2.peek(); } - /** Returns whether the queue is empty. */ public boolean empty() { - return s1.empty() && s2.empty(); + return stk1.isEmpty() && stk2.isEmpty(); + } + + private void move() { + while (stk2.isEmpty()) { + while (!stk1.isEmpty()) { + stk2.push(stk1.pop()); + } + } } } @@ -112,51 +102,92 @@ class MyQueue { */ ``` +```cpp +class MyQueue { +public: + MyQueue() { + } + + void push(int x) { + stk1.push(x); + } + + int pop() { + move(); + int ans = stk2.top(); + stk2.pop(); + return ans; + } + + int peek() { + move(); + return stk2.top(); + } + + bool empty() { + return stk1.empty() && stk2.empty(); + } + +private: + stack stk1; + stack stk2; + + void move() { + if (stk2.empty()) { + while (!stk1.empty()) { + stk2.push(stk1.top()); + stk1.pop(); + } + } + } +}; + +/** + * 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(); + * bool param_4 = obj->empty(); + */ +``` + ```go type MyQueue struct { - s1, s2 []int + stk1 []int + stk2 []int } -/** Initialize your data structure here. */ func Constructor() MyQueue { - return MyQueue{ - s1: make([]int, 0), - s2: make([]int, 0), - } + return MyQueue{[]int{}, []int{}} } -/** Push element x to the back of queue. */ func (this *MyQueue) Push(x int) { - this.s1 = append(this.s1, x) + this.stk1 = append(this.stk1, x) } -/** Removes the element from in front of queue and returns that element. */ func (this *MyQueue) Pop() int { - if len(this.s2) == 0 { - this.transfer() - } - v := this.s2[len(this.s2)-1] - this.s2 = this.s2[:len(this.s2)-1] - return v + this.move() + ans := this.stk2[len(this.stk2)-1] + this.stk2 = this.stk2[:len(this.stk2)-1] + return ans } -/** Get the front element. */ func (this *MyQueue) Peek() int { - if len(this.s2) == 0 { - this.transfer() - } - return this.s2[len(this.s2)-1] + this.move() + return this.stk2[len(this.stk2)-1] } -/** Returns whether the queue is empty. */ func (this *MyQueue) Empty() bool { - return len(this.s1) == 0 && len(this.s2) == 0 + return len(this.stk1) == 0 && len(this.stk2) == 0 } -func (this *MyQueue) transfer() { - for len(this.s1) > 0 { - this.s2 = append(this.s2, this.s1[len(this.s1)-1]) - this.s1 = this.s1[:len(this.s1)-1] +func (this *MyQueue) move() { + if len(this.stk2) == 0 { + for len(this.stk1) > 0 { + this.stk2 = append(this.stk2, this.stk1[len(this.stk1)-1]) + this.stk1 = this.stk1[:len(this.stk1)-1] + } } } @@ -172,39 +203,37 @@ func (this *MyQueue) transfer() { ```ts class MyQueue { - private inStack: number[]; - private outStack: number[]; + stk1: number[]; + stk2: number[]; constructor() { - this.inStack = []; - this.outStack = []; + this.stk1 = []; + this.stk2 = []; } push(x: number): void { - this.inStack.push(x); + this.stk1.push(x); } pop(): number { - if (this.outStack.length === 0) { - this.inToOut(); - } - return this.outStack.pop() ?? -1; + this.move(); + return this.stk2.pop(); } peek(): number { - if (this.outStack.length === 0) { - this.inToOut(); - } - return this.outStack[this.outStack.length - 1] ?? -1; + this.move(); + return this.stk2.at(-1); } empty(): boolean { - return this.inStack.length === 0 && this.outStack.length === 0; + return !this.stk1.length && !this.stk2.length; } - inToOut() { - while (this.inStack.length !== 0) { - this.outStack.push(this.inStack.pop()); + move(): void { + if (!this.stk2.length) { + while (this.stk1.length) { + this.stk2.push(this.stk1.pop()!); + } } } } @@ -219,6 +248,57 @@ class MyQueue { */ ``` +```rust +use std::collections::VecDeque; + +struct MyQueue { + stk1: Vec, + stk2: Vec, +} + +impl MyQueue { + fn new() -> Self { + MyQueue { + stk1: Vec::new(), + stk2: Vec::new(), + } + } + + fn push(&mut self, x: i32) { + self.stk1.push(x); + } + + fn pop(&mut self) -> i32 { + self.move_elements(); + self.stk2.pop().unwrap() + } + + fn peek(&mut self) -> i32 { + self.move_elements(); + *self.stk2.last().unwrap() + } + + fn empty(&self) -> bool { + self.stk1.is_empty() && self.stk2.is_empty() + } + + fn move_elements(&mut self) { + if self.stk2.is_empty() { + while let Some(element) = self.stk1.pop() { + self.stk2.push(element); + } + } + } +}/** + * Your MyQueue object will be instantiated and called as such: + * let obj = MyQueue::new(); + * obj.push(x); + * let ret_2: i32 = obj.pop(); + * let ret_3: i32 = obj.peek(); + * let ret_4: bool = obj.empty(); + */ +``` + diff --git a/lcci/03.04.Implement Queue using Stacks/README_EN.md b/lcci/03.04.Implement Queue using Stacks/README_EN.md index e06cc67a9f111..78b7e19cf7331 100644 --- a/lcci/03.04.Implement Queue using Stacks/README_EN.md +++ b/lcci/03.04.Implement Queue using Stacks/README_EN.md @@ -40,47 +40,44 @@ queue.empty(); // return false ## Solutions -### Solution 1 +### Solution 1: Double Stack + +We use two stacks, where `stk1` is used for enqueue, and another stack `stk2` is used for dequeue. + +When enqueueing, we directly push the element into `stk1`. The time complexity is $O(1)$. + +When dequeueing, we first check whether `stk2` is empty. If it is empty, we pop all elements from `stk1` and push them into `stk2`, and then pop an element from `stk2`. If `stk2` is not empty, we directly pop an element from `stk2`. The amortized time complexity is $O(1)$. + +When getting the front element, we first check whether `stk2` is empty. If it is empty, we pop all elements from `stk1` and push them into `stk2`, and then get the top element from `stk2`. If `stk2` is not empty, we directly get the top element from `stk2`. The amortized time complexity is $O(1)$. + +When checking whether the queue is empty, we only need to check whether both stacks are empty. The time complexity is $O(1)$. ```python class MyQueue: def __init__(self): - """ - Initialize your data structure here. - """ - self._s1, self._s2 = [], [] + self.stk1 = [] + self.stk2 = [] def push(self, x: int) -> None: - """ - Push element x to the back of queue. - """ - self._s1.append(x) + self.stk1.append(x) def pop(self) -> int: - """ - Removes the element from in front of queue and returns that element. - """ - if len(self._s2) == 0: - while self._s1: - self._s2.append(self._s1.pop()) - return self._s2.pop() + self.move() + return self.stk2.pop() def peek(self) -> int: - """ - Get the front element. - """ - if len(self._s2) == 0: - while self._s1: - self._s2.append(self._s1.pop()) - return self._s2[-1] + self.move() + return self.stk2[-1] def empty(self) -> bool: - """ - Returns whether the queue is empty. - """ - return len(self._s1) + len(self._s2) == 0 + return not self.stk1 and not self.stk2 + + def move(self): + if not self.stk2: + while self.stk1: + self.stk2.append(self.stk1.pop()) # Your MyQueue object will be instantiated and called as such: @@ -93,43 +90,36 @@ class MyQueue: ```java class MyQueue { - private Stack s1; - private Stack s2; + private Deque stk1 = new ArrayDeque<>(); + private Deque stk2 = new ArrayDeque<>(); - /** Initialize your data structure here. */ public MyQueue() { - s1 = new Stack<>(); - s2 = new Stack<>(); } - /** Push element x to the back of queue. */ public void push(int x) { - s1.push(x); + stk1.push(x); } - /** Removes the element from in front of queue and returns that element. */ public int pop() { - if (s2.empty()) { - while (!s1.empty()) { - s2.push(s1.pop()); - } - } - return s2.pop(); + move(); + return stk2.pop(); } - /** Get the front element. */ public int peek() { - if (s2.empty()) { - while (!s1.empty()) { - s2.push(s1.pop()); - } - } - return s2.peek(); + move(); + return stk2.peek(); } - /** Returns whether the queue is empty. */ public boolean empty() { - return s1.empty() && s2.empty(); + return stk1.isEmpty() && stk2.isEmpty(); + } + + private void move() { + while (stk2.isEmpty()) { + while (!stk1.isEmpty()) { + stk2.push(stk1.pop()); + } + } } } @@ -143,51 +133,92 @@ class MyQueue { */ ``` +```cpp +class MyQueue { +public: + MyQueue() { + } + + void push(int x) { + stk1.push(x); + } + + int pop() { + move(); + int ans = stk2.top(); + stk2.pop(); + return ans; + } + + int peek() { + move(); + return stk2.top(); + } + + bool empty() { + return stk1.empty() && stk2.empty(); + } + +private: + stack stk1; + stack stk2; + + void move() { + if (stk2.empty()) { + while (!stk1.empty()) { + stk2.push(stk1.top()); + stk1.pop(); + } + } + } +}; + +/** + * 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(); + * bool param_4 = obj->empty(); + */ +``` + ```go type MyQueue struct { - s1, s2 []int + stk1 []int + stk2 []int } -/** Initialize your data structure here. */ func Constructor() MyQueue { - return MyQueue{ - s1: make([]int, 0), - s2: make([]int, 0), - } + return MyQueue{[]int{}, []int{}} } -/** Push element x to the back of queue. */ func (this *MyQueue) Push(x int) { - this.s1 = append(this.s1, x) + this.stk1 = append(this.stk1, x) } -/** Removes the element from in front of queue and returns that element. */ func (this *MyQueue) Pop() int { - if len(this.s2) == 0 { - this.transfer() - } - v := this.s2[len(this.s2)-1] - this.s2 = this.s2[:len(this.s2)-1] - return v + this.move() + ans := this.stk2[len(this.stk2)-1] + this.stk2 = this.stk2[:len(this.stk2)-1] + return ans } -/** Get the front element. */ func (this *MyQueue) Peek() int { - if len(this.s2) == 0 { - this.transfer() - } - return this.s2[len(this.s2)-1] + this.move() + return this.stk2[len(this.stk2)-1] } -/** Returns whether the queue is empty. */ func (this *MyQueue) Empty() bool { - return len(this.s1) == 0 && len(this.s2) == 0 + return len(this.stk1) == 0 && len(this.stk2) == 0 } -func (this *MyQueue) transfer() { - for len(this.s1) > 0 { - this.s2 = append(this.s2, this.s1[len(this.s1)-1]) - this.s1 = this.s1[:len(this.s1)-1] +func (this *MyQueue) move() { + if len(this.stk2) == 0 { + for len(this.stk1) > 0 { + this.stk2 = append(this.stk2, this.stk1[len(this.stk1)-1]) + this.stk1 = this.stk1[:len(this.stk1)-1] + } } } @@ -203,39 +234,37 @@ func (this *MyQueue) transfer() { ```ts class MyQueue { - private inStack: number[]; - private outStack: number[]; + stk1: number[]; + stk2: number[]; constructor() { - this.inStack = []; - this.outStack = []; + this.stk1 = []; + this.stk2 = []; } push(x: number): void { - this.inStack.push(x); + this.stk1.push(x); } pop(): number { - if (this.outStack.length === 0) { - this.inToOut(); - } - return this.outStack.pop() ?? -1; + this.move(); + return this.stk2.pop(); } peek(): number { - if (this.outStack.length === 0) { - this.inToOut(); - } - return this.outStack[this.outStack.length - 1] ?? -1; + this.move(); + return this.stk2.at(-1); } empty(): boolean { - return this.inStack.length === 0 && this.outStack.length === 0; + return !this.stk1.length && !this.stk2.length; } - inToOut() { - while (this.inStack.length !== 0) { - this.outStack.push(this.inStack.pop()); + move(): void { + if (!this.stk2.length) { + while (this.stk1.length) { + this.stk2.push(this.stk1.pop()!); + } } } } @@ -250,6 +279,57 @@ class MyQueue { */ ``` +```rust +use std::collections::VecDeque; + +struct MyQueue { + stk1: Vec, + stk2: Vec, +} + +impl MyQueue { + fn new() -> Self { + MyQueue { + stk1: Vec::new(), + stk2: Vec::new(), + } + } + + fn push(&mut self, x: i32) { + self.stk1.push(x); + } + + fn pop(&mut self) -> i32 { + self.move_elements(); + self.stk2.pop().unwrap() + } + + fn peek(&mut self) -> i32 { + self.move_elements(); + *self.stk2.last().unwrap() + } + + fn empty(&self) -> bool { + self.stk1.is_empty() && self.stk2.is_empty() + } + + fn move_elements(&mut self) { + if self.stk2.is_empty() { + while let Some(element) = self.stk1.pop() { + self.stk2.push(element); + } + } + } +}/** + * Your MyQueue object will be instantiated and called as such: + * let obj = MyQueue::new(); + * obj.push(x); + * let ret_2: i32 = obj.pop(); + * let ret_3: i32 = obj.peek(); + * let ret_4: bool = obj.empty(); + */ +``` + diff --git a/lcci/03.04.Implement Queue using Stacks/Solution.cpp b/lcci/03.04.Implement Queue using Stacks/Solution.cpp new file mode 100644 index 0000000000000..bf48ff66d66e8 --- /dev/null +++ b/lcci/03.04.Implement Queue using Stacks/Solution.cpp @@ -0,0 +1,47 @@ +class MyQueue { +public: + MyQueue() { + } + + void push(int x) { + stk1.push(x); + } + + int pop() { + move(); + int ans = stk2.top(); + stk2.pop(); + return ans; + } + + int peek() { + move(); + return stk2.top(); + } + + bool empty() { + return stk1.empty() && stk2.empty(); + } + +private: + stack stk1; + stack stk2; + + void move() { + if (stk2.empty()) { + while (!stk1.empty()) { + stk2.push(stk1.top()); + stk1.pop(); + } + } + } +}; + +/** + * 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(); + * bool param_4 = obj->empty(); + */ \ No newline at end of file diff --git a/lcci/03.04.Implement Queue using Stacks/Solution.go b/lcci/03.04.Implement Queue using Stacks/Solution.go index d79c5bb8f94d0..ce4bf889a8d1d 100644 --- a/lcci/03.04.Implement Queue using Stacks/Solution.go +++ b/lcci/03.04.Implement Queue using Stacks/Solution.go @@ -1,47 +1,38 @@ type MyQueue struct { - s1, s2 []int + stk1 []int + stk2 []int } -/** Initialize your data structure here. */ func Constructor() MyQueue { - return MyQueue{ - s1: make([]int, 0), - s2: make([]int, 0), - } + return MyQueue{[]int{}, []int{}} } -/** Push element x to the back of queue. */ func (this *MyQueue) Push(x int) { - this.s1 = append(this.s1, x) + this.stk1 = append(this.stk1, x) } -/** Removes the element from in front of queue and returns that element. */ func (this *MyQueue) Pop() int { - if len(this.s2) == 0 { - this.transfer() - } - v := this.s2[len(this.s2)-1] - this.s2 = this.s2[:len(this.s2)-1] - return v + this.move() + ans := this.stk2[len(this.stk2)-1] + this.stk2 = this.stk2[:len(this.stk2)-1] + return ans } -/** Get the front element. */ func (this *MyQueue) Peek() int { - if len(this.s2) == 0 { - this.transfer() - } - return this.s2[len(this.s2)-1] + this.move() + return this.stk2[len(this.stk2)-1] } -/** Returns whether the queue is empty. */ func (this *MyQueue) Empty() bool { - return len(this.s1) == 0 && len(this.s2) == 0 + return len(this.stk1) == 0 && len(this.stk2) == 0 } -func (this *MyQueue) transfer() { - for len(this.s1) > 0 { - this.s2 = append(this.s2, this.s1[len(this.s1)-1]) - this.s1 = this.s1[:len(this.s1)-1] +func (this *MyQueue) move() { + if len(this.stk2) == 0 { + for len(this.stk1) > 0 { + this.stk2 = append(this.stk2, this.stk1[len(this.stk1)-1]) + this.stk1 = this.stk1[:len(this.stk1)-1] + } } } diff --git a/lcci/03.04.Implement Queue using Stacks/Solution.java b/lcci/03.04.Implement Queue using Stacks/Solution.java index 14c34ab11cbe7..626af0e362caa 100644 --- a/lcci/03.04.Implement Queue using Stacks/Solution.java +++ b/lcci/03.04.Implement Queue using Stacks/Solution.java @@ -1,41 +1,34 @@ class MyQueue { - private Stack s1; - private Stack s2; + private Deque stk1 = new ArrayDeque<>(); + private Deque stk2 = new ArrayDeque<>(); - /** Initialize your data structure here. */ public MyQueue() { - s1 = new Stack<>(); - s2 = new Stack<>(); } - /** Push element x to the back of queue. */ public void push(int x) { - s1.push(x); + stk1.push(x); } - /** Removes the element from in front of queue and returns that element. */ public int pop() { - if (s2.empty()) { - while (!s1.empty()) { - s2.push(s1.pop()); - } - } - return s2.pop(); + move(); + return stk2.pop(); } - /** Get the front element. */ public int peek() { - if (s2.empty()) { - while (!s1.empty()) { - s2.push(s1.pop()); - } - } - return s2.peek(); + move(); + return stk2.peek(); } - /** Returns whether the queue is empty. */ public boolean empty() { - return s1.empty() && s2.empty(); + return stk1.isEmpty() && stk2.isEmpty(); + } + + private void move() { + while (stk2.isEmpty()) { + while (!stk1.isEmpty()) { + stk2.push(stk1.pop()); + } + } } } diff --git a/lcci/03.04.Implement Queue using Stacks/Solution.py b/lcci/03.04.Implement Queue using Stacks/Solution.py index 177acbb1de913..33ebd453acfa4 100644 --- a/lcci/03.04.Implement Queue using Stacks/Solution.py +++ b/lcci/03.04.Implement Queue using Stacks/Solution.py @@ -1,39 +1,26 @@ class MyQueue: def __init__(self): - """ - Initialize your data structure here. - """ - self._s1, self._s2 = [], [] + self.stk1 = [] + self.stk2 = [] def push(self, x: int) -> None: - """ - Push element x to the back of queue. - """ - self._s1.append(x) + self.stk1.append(x) def pop(self) -> int: - """ - Removes the element from in front of queue and returns that element. - """ - if len(self._s2) == 0: - while self._s1: - self._s2.append(self._s1.pop()) - return self._s2.pop() + self.move() + return self.stk2.pop() def peek(self) -> int: - """ - Get the front element. - """ - if len(self._s2) == 0: - while self._s1: - self._s2.append(self._s1.pop()) - return self._s2[-1] + self.move() + return self.stk2[-1] def empty(self) -> bool: - """ - Returns whether the queue is empty. - """ - return len(self._s1) + len(self._s2) == 0 + return not self.stk1 and not self.stk2 + + def move(self): + if not self.stk2: + while self.stk1: + self.stk2.append(self.stk1.pop()) # Your MyQueue object will be instantiated and called as such: diff --git a/lcci/03.04.Implement Queue using Stacks/Solution.rs b/lcci/03.04.Implement Queue using Stacks/Solution.rs new file mode 100644 index 0000000000000..a7c5fb57a4170 --- /dev/null +++ b/lcci/03.04.Implement Queue using Stacks/Solution.rs @@ -0,0 +1,48 @@ +use std::collections::VecDeque; + +struct MyQueue { + stk1: Vec, + stk2: Vec, +} + +impl MyQueue { + fn new() -> Self { + MyQueue { + stk1: Vec::new(), + stk2: Vec::new(), + } + } + + fn push(&mut self, x: i32) { + self.stk1.push(x); + } + + fn pop(&mut self) -> i32 { + self.move_elements(); + self.stk2.pop().unwrap() + } + + fn peek(&mut self) -> i32 { + self.move_elements(); + *self.stk2.last().unwrap() + } + + fn empty(&self) -> bool { + self.stk1.is_empty() && self.stk2.is_empty() + } + + fn move_elements(&mut self) { + if self.stk2.is_empty() { + while let Some(element) = self.stk1.pop() { + self.stk2.push(element); + } + } + } +}/** + * Your MyQueue object will be instantiated and called as such: + * let obj = MyQueue::new(); + * obj.push(x); + * let ret_2: i32 = obj.pop(); + * let ret_3: i32 = obj.peek(); + * let ret_4: bool = obj.empty(); + */ diff --git a/lcci/03.04.Implement Queue using Stacks/Solution.ts b/lcci/03.04.Implement Queue using Stacks/Solution.ts index 55947701cc7fd..6ca26efbc57f9 100644 --- a/lcci/03.04.Implement Queue using Stacks/Solution.ts +++ b/lcci/03.04.Implement Queue using Stacks/Solution.ts @@ -1,37 +1,35 @@ class MyQueue { - private inStack: number[]; - private outStack: number[]; + stk1: number[]; + stk2: number[]; constructor() { - this.inStack = []; - this.outStack = []; + this.stk1 = []; + this.stk2 = []; } push(x: number): void { - this.inStack.push(x); + this.stk1.push(x); } pop(): number { - if (this.outStack.length === 0) { - this.inToOut(); - } - return this.outStack.pop() ?? -1; + this.move(); + return this.stk2.pop(); } peek(): number { - if (this.outStack.length === 0) { - this.inToOut(); - } - return this.outStack[this.outStack.length - 1] ?? -1; + this.move(); + return this.stk2.at(-1); } empty(): boolean { - return this.inStack.length === 0 && this.outStack.length === 0; + return !this.stk1.length && !this.stk2.length; } - inToOut() { - while (this.inStack.length !== 0) { - this.outStack.push(this.inStack.pop()); + move(): void { + if (!this.stk2.length) { + while (this.stk1.length) { + this.stk2.push(this.stk1.pop()!); + } } } } diff --git a/solution/0200-0299/0232.Implement Queue using Stacks/README.md b/solution/0200-0299/0232.Implement Queue using Stacks/README.md index dceef8fe5a15c..6a0c77de773f0 100644 --- a/solution/0200-0299/0232.Implement Queue using Stacks/README.md +++ b/solution/0200-0299/0232.Implement Queue using Stacks/README.md @@ -309,50 +309,43 @@ class MyQueue { ``` ```rust +use std::collections::VecDeque; + struct MyQueue { - in_stack: Vec, - out_stack: Vec, + stk1: Vec, + stk2: Vec, } -/** - * `&self` means the method takes an immutable reference. - * If you need a mutable reference, change it to `&mut self` instead. - */ impl MyQueue { fn new() -> Self { - Self { - in_stack: vec![], - out_stack: vec![], + MyQueue { + stk1: Vec::new(), + stk2: Vec::new(), } } fn push(&mut self, x: i32) { - self.in_stack.push(x); + self.stk1.push(x); } fn pop(&mut self) -> i32 { - if self.out_stack.is_empty() { - self.fill_out(); - } - self.out_stack.pop().unwrap() + self.move_elements(); + self.stk2.pop().unwrap() } fn peek(&mut self) -> i32 { - if self.out_stack.is_empty() { - self.fill_out(); - } - *self.out_stack.last().unwrap() + self.move_elements(); + *self.stk2.last().unwrap() } fn empty(&self) -> bool { - self.in_stack.is_empty() && self.out_stack.is_empty() + self.stk1.is_empty() && self.stk2.is_empty() } - fn fill_out(&mut self) { - let MyQueue { in_stack, out_stack } = self; - if out_stack.is_empty() { - while !in_stack.is_empty() { - out_stack.push(in_stack.pop().unwrap()); + fn move_elements(&mut self) { + if self.stk2.is_empty() { + while let Some(element) = self.stk1.pop() { + self.stk2.push(element); } } } diff --git a/solution/0200-0299/0232.Implement Queue using Stacks/README_EN.md b/solution/0200-0299/0232.Implement Queue using Stacks/README_EN.md index 629daa6eb2317..989697558ce3c 100644 --- a/solution/0200-0299/0232.Implement Queue using Stacks/README_EN.md +++ b/solution/0200-0299/0232.Implement Queue using Stacks/README_EN.md @@ -57,7 +57,17 @@ myQueue.empty(); // return false ## Solutions -### Solution 1 +### Solution 1: Double Stack + +We use two stacks, where `stk1` is used for enqueue, and another stack `stk2` is used for dequeue. + +When enqueueing, we directly push the element into `stk1`. The time complexity is $O(1)$. + +When dequeueing, we first check whether `stk2` is empty. If it is empty, we pop all elements from `stk1` and push them into `stk2`, and then pop an element from `stk2`. If `stk2` is not empty, we directly pop an element from `stk2`. The amortized time complexity is $O(1)$. + +When getting the front element, we first check whether `stk2` is empty. If it is empty, we pop all elements from `stk1` and push them into `stk2`, and then get the top element from `stk2`. If `stk2` is not empty, we directly get the top element from `stk2`. The amortized time complexity is $O(1)$. + +When checking whether the queue is empty, we only need to check whether both stacks are empty. The time complexity is $O(1)$. @@ -287,50 +297,43 @@ class MyQueue { ``` ```rust +use std::collections::VecDeque; + struct MyQueue { - in_stack: Vec, - out_stack: Vec, + stk1: Vec, + stk2: Vec, } -/** - * `&self` means the method takes an immutable reference. - * If you need a mutable reference, change it to `&mut self` instead. - */ impl MyQueue { fn new() -> Self { - Self { - in_stack: vec![], - out_stack: vec![], + MyQueue { + stk1: Vec::new(), + stk2: Vec::new(), } } fn push(&mut self, x: i32) { - self.in_stack.push(x); + self.stk1.push(x); } fn pop(&mut self) -> i32 { - if self.out_stack.is_empty() { - self.fill_out(); - } - self.out_stack.pop().unwrap() + self.move_elements(); + self.stk2.pop().unwrap() } fn peek(&mut self) -> i32 { - if self.out_stack.is_empty() { - self.fill_out(); - } - *self.out_stack.last().unwrap() + self.move_elements(); + *self.stk2.last().unwrap() } fn empty(&self) -> bool { - self.in_stack.is_empty() && self.out_stack.is_empty() + self.stk1.is_empty() && self.stk2.is_empty() } - fn fill_out(&mut self) { - let MyQueue { in_stack, out_stack } = self; - if out_stack.is_empty() { - while !in_stack.is_empty() { - out_stack.push(in_stack.pop().unwrap()); + fn move_elements(&mut self) { + if self.stk2.is_empty() { + while let Some(element) = self.stk1.pop() { + self.stk2.push(element); } } } diff --git a/solution/0200-0299/0232.Implement Queue using Stacks/Solution.rs b/solution/0200-0299/0232.Implement Queue using Stacks/Solution.rs index e74f5a6172b15..a7c5fb57a4170 100644 --- a/solution/0200-0299/0232.Implement Queue using Stacks/Solution.rs +++ b/solution/0200-0299/0232.Implement Queue using Stacks/Solution.rs @@ -1,47 +1,40 @@ +use std::collections::VecDeque; + struct MyQueue { - in_stack: Vec, - out_stack: Vec, + stk1: Vec, + stk2: Vec, } -/** - * `&self` means the method takes an immutable reference. - * If you need a mutable reference, change it to `&mut self` instead. - */ impl MyQueue { fn new() -> Self { - Self { - in_stack: vec![], - out_stack: vec![], + MyQueue { + stk1: Vec::new(), + stk2: Vec::new(), } } fn push(&mut self, x: i32) { - self.in_stack.push(x); + self.stk1.push(x); } fn pop(&mut self) -> i32 { - if self.out_stack.is_empty() { - self.fill_out(); - } - self.out_stack.pop().unwrap() + self.move_elements(); + self.stk2.pop().unwrap() } fn peek(&mut self) -> i32 { - if self.out_stack.is_empty() { - self.fill_out(); - } - *self.out_stack.last().unwrap() + self.move_elements(); + *self.stk2.last().unwrap() } fn empty(&self) -> bool { - self.in_stack.is_empty() && self.out_stack.is_empty() + self.stk1.is_empty() && self.stk2.is_empty() } - fn fill_out(&mut self) { - let MyQueue { in_stack, out_stack } = self; - if out_stack.is_empty() { - while !in_stack.is_empty() { - out_stack.push(in_stack.pop().unwrap()); + fn move_elements(&mut self) { + if self.stk2.is_empty() { + while let Some(element) = self.stk1.pop() { + self.stk2.push(element); } } }