> {
let mut dummy = Some(Box::new(ListNode::new(0)));
let mut cur = dummy.as_mut();
diff --git a/lcci/02.05.Sum Lists/Solution.swift b/lcci/02.05.Sum Lists/Solution.swift
new file mode 100644
index 0000000000000..91122ca76b4dd
--- /dev/null
+++ b/lcci/02.05.Sum Lists/Solution.swift
@@ -0,0 +1,30 @@
+/**
+ * Definition for singly-linked list.
+ * public class ListNode {
+ * public var val: Int
+ * public var next: ListNode?
+ * public init(_ val: Int) {
+ * self.val = val
+ * self.next = nil
+ * }
+ * }
+ */
+class Solution {
+ func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? {
+ var carry = 0
+ let dummy = ListNode(0)
+ var current: ListNode? = dummy
+ var l1 = l1, l2 = l2
+
+ while l1 != nil || l2 != nil || carry != 0 {
+ let sum = (l1?.val ?? 0) + (l2?.val ?? 0) + carry
+ carry = sum / 10
+ current?.next = ListNode(sum % 10)
+ current = current?.next
+ l1 = l1?.next
+ l2 = l2?.next
+ }
+
+ return dummy.next
+ }
+}
\ No newline at end of file
diff --git a/lcci/02.06.Palindrome Linked List/README.md b/lcci/02.06.Palindrome Linked List/README.md
index 9abc0cd6a8e25..7522e99791c51 100644
--- a/lcci/02.06.Palindrome Linked List/README.md
+++ b/lcci/02.06.Palindrome Linked List/README.md
@@ -1,10 +1,19 @@
+---
+comments: true
+difficulty: 简单
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/02.06.Palindrome%20Linked%20List/README.md
+---
+
+
+
# [面试题 02.06. 回文链表](https://leetcode.cn/problems/palindrome-linked-list-lcci)
[English Version](/lcci/02.06.Palindrome%20Linked%20List/README_EN.md)
## 题目描述
-
+
+
编写一个函数,检查输入的链表是否是回文的。
@@ -26,51 +35,73 @@
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
+
+
## 解法
-### 方法一
+
+
+### 方法一:快慢指针 + 反转链表
+
+我们首先判断链表是否为空,如果为空,直接返回 `true`。
+
+接下来,我们使用快慢指针找到链表的中点,如果链表长度为奇数,那么慢指针指向的就是中点,如果链表长度为偶数,那么慢指针指向的是中间两个节点的前一个节点。
+
+然后,我们将慢指针之后的链表反转,这样我们就得到了链表的后半部分,其中链表头节点为 $p$。
+
+最后,我们循环比较链表的前半部分和后半部分,如果有不相等的节点,直接返回 `false`,否则遍历完链表后返回 `true`。
+
+时间复杂度 $O(n)$,其中 $n$ 为链表的长度。空间复杂度 $O(1)$。
+#### Python3
+
```python
# Definition for singly-linked list.
# class ListNode:
-# def __init__(self, val=0, next=None):
-# self.val = val
-# self.next = next
+# def __init__(self, x):
+# self.val = x
+# self.next = None
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
- if head is None or head.next is None:
+ if head is None:
return True
slow, fast = head, head.next
while fast and fast.next:
- slow, fast = slow.next, fast.next.next
- pre, cur = None, slow.next
- while cur:
- t = cur.next
- cur.next = pre
- pre, cur = cur, t
- while pre:
- if pre.val != head.val:
+ slow = slow.next
+ fast = fast.next.next
+ p = slow.next
+ slow.next = None
+ dummy = ListNode()
+ while p:
+ next = p.next
+ p.next = dummy.next
+ dummy.next = p
+ p = next
+ p = dummy.next
+ while p:
+ if head.val != p.val:
return False
- pre, head = pre.next, head.next
+ head = head.next
+ p = p.next
return True
```
+#### Java
+
```java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
- * ListNode() {}
- * ListNode(int val) { this.val = val; }
- * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
+ * ListNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
- if (head == null || head.next == null) {
+ if (head == null) {
return true;
}
ListNode slow = head;
@@ -79,70 +110,114 @@ class Solution {
slow = slow.next;
fast = fast.next.next;
}
- ListNode cur = slow.next;
+ ListNode p = slow.next;
slow.next = null;
- ListNode pre = null;
- while (cur != null) {
- ListNode t = cur.next;
- cur.next = pre;
- pre = cur;
- cur = t;
+ ListNode dummy = new ListNode(0);
+ while (p != null) {
+ ListNode next = p.next;
+ p.next = dummy.next;
+ dummy.next = p;
+ p = next;
}
- while (pre != null) {
- if (pre.val != head.val) {
+ p = dummy.next;
+ while (p != null) {
+ if (head.val != p.val) {
return false;
}
- pre = pre.next;
head = head.next;
+ p = p.next;
}
return true;
}
}
```
+#### C++
+
+```cpp
+/**
+ * Definition for singly-linked list.
+ * struct ListNode {
+ * int val;
+ * ListNode *next;
+ * ListNode(int x) : val(x), next(NULL) {}
+ * };
+ */
+class Solution {
+public:
+ bool isPalindrome(ListNode* head) {
+ if (!head) {
+ return true;
+ }
+ ListNode* slow = head;
+ ListNode* fast = head->next;
+ while (fast && fast->next) {
+ slow = slow->next;
+ fast = fast->next->next;
+ }
+ ListNode* p = slow->next;
+ slow->next = nullptr;
+ ListNode* dummy = new ListNode(0);
+ while (p) {
+ ListNode* next = p->next;
+ p->next = dummy->next;
+ dummy->next = p;
+ p = next;
+ }
+ p = dummy->next;
+ while (p) {
+ if (head->val != p->val) {
+ return false;
+ }
+ head = head->next;
+ p = p->next;
+ }
+ return true;
+ }
+};
+```
+
+#### Go
+
```go
+/**
+ * Definition for singly-linked list.
+ * type ListNode struct {
+ * Val int
+ * Next *ListNode
+ * }
+ */
func isPalindrome(head *ListNode) bool {
if head == nil {
return true
}
- m := mid(head)
- temp := reverse(m.Next)
- m.Next = nil
- p, q := head, temp
- res := true
- for p != nil && q != nil {
- if p.Val != q.Val {
- res = false
- break
- }
- p = p.Next
- q = q.Next
- }
- m.Next = reverse(temp)
- return res
-}
-
-func mid(head *ListNode) *ListNode {
slow, fast := head, head.Next
for fast != nil && fast.Next != nil {
- slow = slow.Next
- fast = fast.Next.Next
+ slow, fast = slow.Next, fast.Next.Next
}
- return slow
-}
-
-func reverse(head *ListNode) *ListNode {
- var prev *ListNode = nil
- for head != nil {
- temp := head.Next
- head.Next = prev
- prev = head
- head = temp
+ p := slow.Next
+ slow.Next = nil
+ dummy := &ListNode{}
+ for p != nil {
+ next := p.Next
+ p.Next = dummy.Next
+ dummy.Next = p
+ p = next
}
- return prev
+ p = dummy.Next
+ for p != nil {
+ if head.Val != p.Val {
+ return false
+ }
+ head = head.Next
+ p = p.Next
+ }
+ return true
}
```
+#### TypeScript
+
```ts
/**
* Definition for singly-linked list.
@@ -157,40 +232,44 @@ func reverse(head *ListNode) *ListNode {
*/
function isPalindrome(head: ListNode | null): boolean {
- if (head == null || head.next == null) return true;
- // 快慢指针定位到中点
- let slow: ListNode = head,
- fast: ListNode = head.next;
- while (fast != null && fast.next != null) {
+ if (!head) {
+ return true;
+ }
+ let slow = head;
+ let fast = head.next;
+ while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
}
- // 翻转链表
- let cur: ListNode = slow.next;
+ let p = slow.next;
slow.next = null;
- let prev: ListNode = null;
- while (cur != null) {
- let t: ListNode = cur.next;
- cur.next = prev;
- prev = cur;
- cur = t;
+ const dummy = new ListNode(0);
+ while (p) {
+ const next = p.next;
+ p.next = dummy.next;
+ dummy.next = p;
+ p = next;
}
- // 判断回文
- while (prev != null) {
- if (prev.val != head.val) return false;
- prev = prev.next;
+ p = dummy.next;
+ while (p) {
+ if (head.val !== p.val) {
+ return false;
+ }
head = head.next;
+ p = p.next;
}
return true;
}
```
+#### JavaScript
+
```js
/**
* Definition for singly-linked list.
- * function ListNode(val, next) {
- * this.val = (val===undefined ? 0 : val)
- * this.next = (next===undefined ? null : next)
+ * function ListNode(val) {
+ * this.val = val;
+ * this.next = null;
* }
*/
/**
@@ -198,7 +277,7 @@ function isPalindrome(head: ListNode | null): boolean {
* @return {boolean}
*/
var isPalindrome = function (head) {
- if (!head || !head.next) {
+ if (!head) {
return true;
}
let slow = head;
@@ -207,110 +286,126 @@ var isPalindrome = function (head) {
slow = slow.next;
fast = fast.next.next;
}
- let cur = slow.next;
+ let p = slow.next;
slow.next = null;
- let pre = null;
- while (cur) {
- let t = cur.next;
- cur.next = pre;
- pre = cur;
- cur = t;
+ const dummy = new ListNode(0);
+ while (p) {
+ const next = p.next;
+ p.next = dummy.next;
+ dummy.next = p;
+ p = next;
}
- while (pre) {
- if (pre.val !== head.val) {
+ p = dummy.next;
+ while (p) {
+ if (head.val !== p.val) {
return false;
}
- pre = pre.next;
head = head.next;
+ p = p.next;
}
return true;
};
```
+#### C#
+
```cs
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
- * public ListNode(int val=0, ListNode next=null) {
- * this.val = val;
- * this.next = next;
- * }
+ * public ListNode(int x) { val = x; }
* }
*/
public class Solution {
public bool IsPalindrome(ListNode head) {
- if (head == null || head.next == null)
- {
+ if (head == null) {
return true;
}
ListNode slow = head;
ListNode fast = head.next;
- while (fast != null && fast.next != null)
- {
+ while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
- ListNode cur = slow.next;
+ ListNode p = slow.next;
slow.next = null;
- ListNode pre = null;
- while (cur != null)
- {
- ListNode t = cur.next;
- cur.next = pre;
- pre = cur;
- cur = t;
+ ListNode dummy = new ListNode(0);
+ while (p != null) {
+ ListNode next = p.next;
+ p.next = dummy.next;
+ dummy.next = p;
+ p = next;
}
- while (pre != null)
- {
- if (pre.val != head.val)
- {
+ p = dummy.next;
+ while (p != null) {
+ if (head.val != p.val) {
return false;
}
- pre = pre.next;
head = head.next;
+ p = p.next;
}
return true;
}
}
```
-
+#### Swift
-### 方法二
+```swift
+/**
+* public class ListNode {
+* var val: Int
+* var next: ListNode?
+* init(_ x: Int) {
+* self.val = x
+* self.next = nil
+* }
+* }
+*/
-
+class Solution {
+ func isPalindrome(_ head: ListNode?) -> Bool {
+ if head == nil {
+ return true
+ }
-```ts
-/**
- * Definition for singly-linked list.
- * class ListNode {
- * val: number
- * next: ListNode | null
- * constructor(val?: number, next?: ListNode | null) {
- * this.val = (val===undefined ? 0 : val)
- * this.next = (next===undefined ? null : next)
- * }
- * }
- */
+ var slow = head
+ var fast = head?.next
+ while fast != nil && fast?.next != nil {
+ slow = slow?.next
+ fast = fast?.next?.next
+ }
-function isPalindrome(head: ListNode | null): boolean {
- let root = head;
- const dfs = (node: ListNode | null): boolean => {
- if (node == null) {
- return true;
+ var p = slow?.next
+ slow?.next = nil
+ var dummy = ListNode(0)
+
+ while p != nil {
+ let next = p?.next
+ p?.next = dummy.next
+ dummy.next = p
+ p = next
}
- if (dfs(node.next) && node.val === root.val) {
- root = root.next;
- return true;
+
+ p = dummy.next
+ var currentHead = head
+ while p != nil {
+ if currentHead?.val != p?.val {
+ return false
+ }
+ currentHead = currentHead?.next
+ p = p?.next
}
- return false;
- };
- return dfs(head);
+
+ return true
+ }
}
```
-
+
+
+
diff --git a/lcci/02.06.Palindrome Linked List/README_EN.md b/lcci/02.06.Palindrome Linked List/README_EN.md
index 3bf8f86c4af95..00baf684a1ef3 100644
--- a/lcci/02.06.Palindrome Linked List/README_EN.md
+++ b/lcci/02.06.Palindrome Linked List/README_EN.md
@@ -1,9 +1,19 @@
+---
+comments: true
+difficulty: Easy
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/02.06.Palindrome%20Linked%20List/README_EN.md
+---
+
+
+
# [02.06. Palindrome Linked List](https://leetcode.cn/problems/palindrome-linked-list-lcci)
[中文文档](/lcci/02.06.Palindrome%20Linked%20List/README.md)
## Description
+
+
Implement a function to check if a linked list is a palindrome.
@@ -34,51 +44,73 @@
Could you do it in O(n) time and O(1) space?
+
+
## Solutions
-### Solution 1
+
+
+### Solution 1: Fast and Slow Pointers + Reverse List
+
+First, we check if the list is empty. If it is, we return `true` directly.
+
+Next, we use fast and slow pointers to find the midpoint of the list. If the length of the list is odd, the slow pointer points to the midpoint. If the length of the list is even, the slow pointer points to the first of the two middle nodes.
+
+Then, we reverse the list after the slow pointer, giving us the second half of the list, with the head node as $p$.
+
+Finally, we loop to compare the first half and the second half of the list. If there are any unequal nodes, we return `false` directly. Otherwise, we return `true` after traversing the list.
+
+The time complexity is $O(n)$, where $n$ is the length of the list. The space complexity is $O(1)$.
+#### Python3
+
```python
# Definition for singly-linked list.
# class ListNode:
-# def __init__(self, val=0, next=None):
-# self.val = val
-# self.next = next
+# def __init__(self, x):
+# self.val = x
+# self.next = None
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
- if head is None or head.next is None:
+ if head is None:
return True
slow, fast = head, head.next
while fast and fast.next:
- slow, fast = slow.next, fast.next.next
- pre, cur = None, slow.next
- while cur:
- t = cur.next
- cur.next = pre
- pre, cur = cur, t
- while pre:
- if pre.val != head.val:
+ slow = slow.next
+ fast = fast.next.next
+ p = slow.next
+ slow.next = None
+ dummy = ListNode()
+ while p:
+ next = p.next
+ p.next = dummy.next
+ dummy.next = p
+ p = next
+ p = dummy.next
+ while p:
+ if head.val != p.val:
return False
- pre, head = pre.next, head.next
+ head = head.next
+ p = p.next
return True
```
+#### Java
+
```java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
- * ListNode() {}
- * ListNode(int val) { this.val = val; }
- * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
+ * ListNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
- if (head == null || head.next == null) {
+ if (head == null) {
return true;
}
ListNode slow = head;
@@ -87,70 +119,114 @@ class Solution {
slow = slow.next;
fast = fast.next.next;
}
- ListNode cur = slow.next;
+ ListNode p = slow.next;
slow.next = null;
- ListNode pre = null;
- while (cur != null) {
- ListNode t = cur.next;
- cur.next = pre;
- pre = cur;
- cur = t;
+ ListNode dummy = new ListNode(0);
+ while (p != null) {
+ ListNode next = p.next;
+ p.next = dummy.next;
+ dummy.next = p;
+ p = next;
}
- while (pre != null) {
- if (pre.val != head.val) {
+ p = dummy.next;
+ while (p != null) {
+ if (head.val != p.val) {
return false;
}
- pre = pre.next;
head = head.next;
+ p = p.next;
}
return true;
}
}
```
+#### C++
+
+```cpp
+/**
+ * Definition for singly-linked list.
+ * struct ListNode {
+ * int val;
+ * ListNode *next;
+ * ListNode(int x) : val(x), next(NULL) {}
+ * };
+ */
+class Solution {
+public:
+ bool isPalindrome(ListNode* head) {
+ if (!head) {
+ return true;
+ }
+ ListNode* slow = head;
+ ListNode* fast = head->next;
+ while (fast && fast->next) {
+ slow = slow->next;
+ fast = fast->next->next;
+ }
+ ListNode* p = slow->next;
+ slow->next = nullptr;
+ ListNode* dummy = new ListNode(0);
+ while (p) {
+ ListNode* next = p->next;
+ p->next = dummy->next;
+ dummy->next = p;
+ p = next;
+ }
+ p = dummy->next;
+ while (p) {
+ if (head->val != p->val) {
+ return false;
+ }
+ head = head->next;
+ p = p->next;
+ }
+ return true;
+ }
+};
+```
+
+#### Go
+
```go
+/**
+ * Definition for singly-linked list.
+ * type ListNode struct {
+ * Val int
+ * Next *ListNode
+ * }
+ */
func isPalindrome(head *ListNode) bool {
if head == nil {
return true
}
- m := mid(head)
- temp := reverse(m.Next)
- m.Next = nil
- p, q := head, temp
- res := true
- for p != nil && q != nil {
- if p.Val != q.Val {
- res = false
- break
- }
- p = p.Next
- q = q.Next
- }
- m.Next = reverse(temp)
- return res
-}
-
-func mid(head *ListNode) *ListNode {
slow, fast := head, head.Next
for fast != nil && fast.Next != nil {
- slow = slow.Next
- fast = fast.Next.Next
+ slow, fast = slow.Next, fast.Next.Next
}
- return slow
-}
-
-func reverse(head *ListNode) *ListNode {
- var prev *ListNode = nil
- for head != nil {
- temp := head.Next
- head.Next = prev
- prev = head
- head = temp
+ p := slow.Next
+ slow.Next = nil
+ dummy := &ListNode{}
+ for p != nil {
+ next := p.Next
+ p.Next = dummy.Next
+ dummy.Next = p
+ p = next
}
- return prev
+ p = dummy.Next
+ for p != nil {
+ if head.Val != p.Val {
+ return false
+ }
+ head = head.Next
+ p = p.Next
+ }
+ return true
}
```
+#### TypeScript
+
```ts
/**
* Definition for singly-linked list.
@@ -165,40 +241,44 @@ func reverse(head *ListNode) *ListNode {
*/
function isPalindrome(head: ListNode | null): boolean {
- if (head == null || head.next == null) return true;
- // 快慢指针定位到中点
- let slow: ListNode = head,
- fast: ListNode = head.next;
- while (fast != null && fast.next != null) {
+ if (!head) {
+ return true;
+ }
+ let slow = head;
+ let fast = head.next;
+ while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
}
- // 翻转链表
- let cur: ListNode = slow.next;
+ let p = slow.next;
slow.next = null;
- let prev: ListNode = null;
- while (cur != null) {
- let t: ListNode = cur.next;
- cur.next = prev;
- prev = cur;
- cur = t;
+ const dummy = new ListNode(0);
+ while (p) {
+ const next = p.next;
+ p.next = dummy.next;
+ dummy.next = p;
+ p = next;
}
- // 判断回文
- while (prev != null) {
- if (prev.val != head.val) return false;
- prev = prev.next;
+ p = dummy.next;
+ while (p) {
+ if (head.val !== p.val) {
+ return false;
+ }
head = head.next;
+ p = p.next;
}
return true;
}
```
+#### JavaScript
+
```js
/**
* Definition for singly-linked list.
- * function ListNode(val, next) {
- * this.val = (val===undefined ? 0 : val)
- * this.next = (next===undefined ? null : next)
+ * function ListNode(val) {
+ * this.val = val;
+ * this.next = null;
* }
*/
/**
@@ -206,7 +286,7 @@ function isPalindrome(head: ListNode | null): boolean {
* @return {boolean}
*/
var isPalindrome = function (head) {
- if (!head || !head.next) {
+ if (!head) {
return true;
}
let slow = head;
@@ -215,110 +295,126 @@ var isPalindrome = function (head) {
slow = slow.next;
fast = fast.next.next;
}
- let cur = slow.next;
+ let p = slow.next;
slow.next = null;
- let pre = null;
- while (cur) {
- let t = cur.next;
- cur.next = pre;
- pre = cur;
- cur = t;
+ const dummy = new ListNode(0);
+ while (p) {
+ const next = p.next;
+ p.next = dummy.next;
+ dummy.next = p;
+ p = next;
}
- while (pre) {
- if (pre.val !== head.val) {
+ p = dummy.next;
+ while (p) {
+ if (head.val !== p.val) {
return false;
}
- pre = pre.next;
head = head.next;
+ p = p.next;
}
return true;
};
```
+#### C#
+
```cs
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
- * public ListNode(int val=0, ListNode next=null) {
- * this.val = val;
- * this.next = next;
- * }
+ * public ListNode(int x) { val = x; }
* }
*/
public class Solution {
public bool IsPalindrome(ListNode head) {
- if (head == null || head.next == null)
- {
+ if (head == null) {
return true;
}
ListNode slow = head;
ListNode fast = head.next;
- while (fast != null && fast.next != null)
- {
+ while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
- ListNode cur = slow.next;
+ ListNode p = slow.next;
slow.next = null;
- ListNode pre = null;
- while (cur != null)
- {
- ListNode t = cur.next;
- cur.next = pre;
- pre = cur;
- cur = t;
+ ListNode dummy = new ListNode(0);
+ while (p != null) {
+ ListNode next = p.next;
+ p.next = dummy.next;
+ dummy.next = p;
+ p = next;
}
- while (pre != null)
- {
- if (pre.val != head.val)
- {
+ p = dummy.next;
+ while (p != null) {
+ if (head.val != p.val) {
return false;
}
- pre = pre.next;
head = head.next;
+ p = p.next;
}
return true;
}
}
```
-
+#### Swift
-### Solution 2
+```swift
+/**
+* public class ListNode {
+* var val: Int
+* var next: ListNode?
+* init(_ x: Int) {
+* self.val = x
+* self.next = nil
+* }
+* }
+*/
-
+class Solution {
+ func isPalindrome(_ head: ListNode?) -> Bool {
+ if head == nil {
+ return true
+ }
-```ts
-/**
- * Definition for singly-linked list.
- * class ListNode {
- * val: number
- * next: ListNode | null
- * constructor(val?: number, next?: ListNode | null) {
- * this.val = (val===undefined ? 0 : val)
- * this.next = (next===undefined ? null : next)
- * }
- * }
- */
+ var slow = head
+ var fast = head?.next
+ while fast != nil && fast?.next != nil {
+ slow = slow?.next
+ fast = fast?.next?.next
+ }
-function isPalindrome(head: ListNode | null): boolean {
- let root = head;
- const dfs = (node: ListNode | null): boolean => {
- if (node == null) {
- return true;
+ var p = slow?.next
+ slow?.next = nil
+ var dummy = ListNode(0)
+
+ while p != nil {
+ let next = p?.next
+ p?.next = dummy.next
+ dummy.next = p
+ p = next
}
- if (dfs(node.next) && node.val === root.val) {
- root = root.next;
- return true;
+
+ p = dummy.next
+ var currentHead = head
+ while p != nil {
+ if currentHead?.val != p?.val {
+ return false
+ }
+ currentHead = currentHead?.next
+ p = p?.next
}
- return false;
- };
- return dfs(head);
+
+ return true
+ }
}
```
-
+
+
+
diff --git a/lcci/02.06.Palindrome Linked List/Solution.cpp b/lcci/02.06.Palindrome Linked List/Solution.cpp
new file mode 100644
index 0000000000000..426f6feca1cf4
--- /dev/null
+++ b/lcci/02.06.Palindrome Linked List/Solution.cpp
@@ -0,0 +1,40 @@
+/**
+ * Definition for singly-linked list.
+ * struct ListNode {
+ * int val;
+ * ListNode *next;
+ * ListNode(int x) : val(x), next(NULL) {}
+ * };
+ */
+class Solution {
+public:
+ bool isPalindrome(ListNode* head) {
+ if (!head) {
+ return true;
+ }
+ ListNode* slow = head;
+ ListNode* fast = head->next;
+ while (fast && fast->next) {
+ slow = slow->next;
+ fast = fast->next->next;
+ }
+ ListNode* p = slow->next;
+ slow->next = nullptr;
+ ListNode* dummy = new ListNode(0);
+ while (p) {
+ ListNode* next = p->next;
+ p->next = dummy->next;
+ dummy->next = p;
+ p = next;
+ }
+ p = dummy->next;
+ while (p) {
+ if (head->val != p->val) {
+ return false;
+ }
+ head = head->next;
+ p = p->next;
+ }
+ return true;
+ }
+};
\ No newline at end of file
diff --git a/lcci/02.06.Palindrome Linked List/Solution.cs b/lcci/02.06.Palindrome Linked List/Solution.cs
index 47f9d260e262f..ab3c68ec8e3b8 100644
--- a/lcci/02.06.Palindrome Linked List/Solution.cs
+++ b/lcci/02.06.Palindrome Linked List/Solution.cs
@@ -3,44 +3,37 @@
* public class ListNode {
* public int val;
* public ListNode next;
- * public ListNode(int val=0, ListNode next=null) {
- * this.val = val;
- * this.next = next;
- * }
+ * public ListNode(int x) { val = x; }
* }
*/
public class Solution {
public bool IsPalindrome(ListNode head) {
- if (head == null || head.next == null)
- {
+ if (head == null) {
return true;
}
ListNode slow = head;
ListNode fast = head.next;
- while (fast != null && fast.next != null)
- {
+ while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
- ListNode cur = slow.next;
+ ListNode p = slow.next;
slow.next = null;
- ListNode pre = null;
- while (cur != null)
- {
- ListNode t = cur.next;
- cur.next = pre;
- pre = cur;
- cur = t;
+ ListNode dummy = new ListNode(0);
+ while (p != null) {
+ ListNode next = p.next;
+ p.next = dummy.next;
+ dummy.next = p;
+ p = next;
}
- while (pre != null)
- {
- if (pre.val != head.val)
- {
+ p = dummy.next;
+ while (p != null) {
+ if (head.val != p.val) {
return false;
}
- pre = pre.next;
head = head.next;
+ p = p.next;
}
return true;
}
-}
+}
\ No newline at end of file
diff --git a/lcci/02.06.Palindrome Linked List/Solution.go b/lcci/02.06.Palindrome Linked List/Solution.go
index 21d6aaad07686..4bf293c100926 100644
--- a/lcci/02.06.Palindrome Linked List/Solution.go
+++ b/lcci/02.06.Palindrome Linked List/Solution.go
@@ -1,40 +1,34 @@
+/**
+ * Definition for singly-linked list.
+ * type ListNode struct {
+ * Val int
+ * Next *ListNode
+ * }
+ */
func isPalindrome(head *ListNode) bool {
if head == nil {
return true
}
- m := mid(head)
- temp := reverse(m.Next)
- m.Next = nil
- p, q := head, temp
- res := true
- for p != nil && q != nil {
- if p.Val != q.Val {
- res = false
- break
- }
- p = p.Next
- q = q.Next
- }
- m.Next = reverse(temp)
- return res
-}
-
-func mid(head *ListNode) *ListNode {
slow, fast := head, head.Next
for fast != nil && fast.Next != nil {
- slow = slow.Next
- fast = fast.Next.Next
+ slow, fast = slow.Next, fast.Next.Next
}
- return slow
-}
-
-func reverse(head *ListNode) *ListNode {
- var prev *ListNode = nil
- for head != nil {
- temp := head.Next
- head.Next = prev
- prev = head
- head = temp
+ p := slow.Next
+ slow.Next = nil
+ dummy := &ListNode{}
+ for p != nil {
+ next := p.Next
+ p.Next = dummy.Next
+ dummy.Next = p
+ p = next
+ }
+ p = dummy.Next
+ for p != nil {
+ if head.Val != p.Val {
+ return false
+ }
+ head = head.Next
+ p = p.Next
}
- return prev
+ return true
}
\ No newline at end of file
diff --git a/lcci/02.06.Palindrome Linked List/Solution.java b/lcci/02.06.Palindrome Linked List/Solution.java
index d095bf315e1d1..348a003f84e01 100644
--- a/lcci/02.06.Palindrome Linked List/Solution.java
+++ b/lcci/02.06.Palindrome Linked List/Solution.java
@@ -3,14 +3,12 @@
* public class ListNode {
* int val;
* ListNode next;
- * ListNode() {}
- * ListNode(int val) { this.val = val; }
- * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
+ * ListNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
- if (head == null || head.next == null) {
+ if (head == null) {
return true;
}
ListNode slow = head;
@@ -19,21 +17,22 @@ public boolean isPalindrome(ListNode head) {
slow = slow.next;
fast = fast.next.next;
}
- ListNode cur = slow.next;
+ ListNode p = slow.next;
slow.next = null;
- ListNode pre = null;
- while (cur != null) {
- ListNode t = cur.next;
- cur.next = pre;
- pre = cur;
- cur = t;
+ ListNode dummy = new ListNode(0);
+ while (p != null) {
+ ListNode next = p.next;
+ p.next = dummy.next;
+ dummy.next = p;
+ p = next;
}
- while (pre != null) {
- if (pre.val != head.val) {
+ p = dummy.next;
+ while (p != null) {
+ if (head.val != p.val) {
return false;
}
- pre = pre.next;
head = head.next;
+ p = p.next;
}
return true;
}
diff --git a/lcci/02.06.Palindrome Linked List/Solution.js b/lcci/02.06.Palindrome Linked List/Solution.js
index c82a575902a76..3928cb7de527e 100644
--- a/lcci/02.06.Palindrome Linked List/Solution.js
+++ b/lcci/02.06.Palindrome Linked List/Solution.js
@@ -1,8 +1,8 @@
/**
* Definition for singly-linked list.
- * function ListNode(val, next) {
- * this.val = (val===undefined ? 0 : val)
- * this.next = (next===undefined ? null : next)
+ * function ListNode(val) {
+ * this.val = val;
+ * this.next = null;
* }
*/
/**
@@ -10,7 +10,7 @@
* @return {boolean}
*/
var isPalindrome = function (head) {
- if (!head || !head.next) {
+ if (!head) {
return true;
}
let slow = head;
@@ -19,21 +19,22 @@ var isPalindrome = function (head) {
slow = slow.next;
fast = fast.next.next;
}
- let cur = slow.next;
+ let p = slow.next;
slow.next = null;
- let pre = null;
- while (cur) {
- let t = cur.next;
- cur.next = pre;
- pre = cur;
- cur = t;
+ const dummy = new ListNode(0);
+ while (p) {
+ const next = p.next;
+ p.next = dummy.next;
+ dummy.next = p;
+ p = next;
}
- while (pre) {
- if (pre.val !== head.val) {
+ p = dummy.next;
+ while (p) {
+ if (head.val !== p.val) {
return false;
}
- pre = pre.next;
head = head.next;
+ p = p.next;
}
return true;
};
diff --git a/lcci/02.06.Palindrome Linked List/Solution.py b/lcci/02.06.Palindrome Linked List/Solution.py
index cde1464d10ac9..f0e674be87147 100644
--- a/lcci/02.06.Palindrome Linked List/Solution.py
+++ b/lcci/02.06.Palindrome Linked List/Solution.py
@@ -1,22 +1,28 @@
# Definition for singly-linked list.
# class ListNode:
-# def __init__(self, val=0, next=None):
-# self.val = val
-# self.next = next
+# def __init__(self, x):
+# self.val = x
+# self.next = None
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
- if head is None or head.next is None:
+ if head is None:
return True
slow, fast = head, head.next
while fast and fast.next:
- slow, fast = slow.next, fast.next.next
- pre, cur = None, slow.next
- while cur:
- t = cur.next
- cur.next = pre
- pre, cur = cur, t
- while pre:
- if pre.val != head.val:
+ slow = slow.next
+ fast = fast.next.next
+ p = slow.next
+ slow.next = None
+ dummy = ListNode()
+ while p:
+ next = p.next
+ p.next = dummy.next
+ dummy.next = p
+ p = next
+ p = dummy.next
+ while p:
+ if head.val != p.val:
return False
- pre, head = pre.next, head.next
+ head = head.next
+ p = p.next
return True
diff --git a/lcci/02.06.Palindrome Linked List/Solution.swift b/lcci/02.06.Palindrome Linked List/Solution.swift
new file mode 100644
index 0000000000000..327d0d8979403
--- /dev/null
+++ b/lcci/02.06.Palindrome Linked List/Solution.swift
@@ -0,0 +1,48 @@
+/**
+* public class ListNode {
+* var val: Int
+* var next: ListNode?
+* init(_ x: Int) {
+* self.val = x
+* self.next = nil
+* }
+* }
+*/
+
+class Solution {
+ func isPalindrome(_ head: ListNode?) -> Bool {
+ if head == nil {
+ return true
+ }
+
+ var slow = head
+ var fast = head?.next
+ while fast != nil && fast?.next != nil {
+ slow = slow?.next
+ fast = fast?.next?.next
+ }
+
+ var p = slow?.next
+ slow?.next = nil
+ var dummy = ListNode(0)
+
+ while p != nil {
+ let next = p?.next
+ p?.next = dummy.next
+ dummy.next = p
+ p = next
+ }
+
+ p = dummy.next
+ var currentHead = head
+ while p != nil {
+ if currentHead?.val != p?.val {
+ return false
+ }
+ currentHead = currentHead?.next
+ p = p?.next
+ }
+
+ return true
+ }
+}
diff --git a/lcci/02.06.Palindrome Linked List/Solution.ts b/lcci/02.06.Palindrome Linked List/Solution.ts
index 36f383eed4006..2474f1177bc09 100644
--- a/lcci/02.06.Palindrome Linked List/Solution.ts
+++ b/lcci/02.06.Palindrome Linked List/Solution.ts
@@ -11,29 +11,31 @@
*/
function isPalindrome(head: ListNode | null): boolean {
- if (head == null || head.next == null) return true;
- // 快慢指针定位到中点
- let slow: ListNode = head,
- fast: ListNode = head.next;
- while (fast != null && fast.next != null) {
+ if (!head) {
+ return true;
+ }
+ let slow = head;
+ let fast = head.next;
+ while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
}
- // 翻转链表
- let cur: ListNode = slow.next;
+ let p = slow.next;
slow.next = null;
- let prev: ListNode = null;
- while (cur != null) {
- let t: ListNode = cur.next;
- cur.next = prev;
- prev = cur;
- cur = t;
+ const dummy = new ListNode(0);
+ while (p) {
+ const next = p.next;
+ p.next = dummy.next;
+ dummy.next = p;
+ p = next;
}
- // 判断回文
- while (prev != null) {
- if (prev.val != head.val) return false;
- prev = prev.next;
+ p = dummy.next;
+ while (p) {
+ if (head.val !== p.val) {
+ return false;
+ }
head = head.next;
+ p = p.next;
}
return true;
}
diff --git a/lcci/02.06.Palindrome Linked List/Solution2.ts b/lcci/02.06.Palindrome Linked List/Solution2.ts
deleted file mode 100644
index 4088bd0df53ff..0000000000000
--- a/lcci/02.06.Palindrome Linked List/Solution2.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Definition for singly-linked list.
- * class ListNode {
- * val: number
- * next: ListNode | null
- * constructor(val?: number, next?: ListNode | null) {
- * this.val = (val===undefined ? 0 : val)
- * this.next = (next===undefined ? null : next)
- * }
- * }
- */
-
-function isPalindrome(head: ListNode | null): boolean {
- let root = head;
- const dfs = (node: ListNode | null): boolean => {
- if (node == null) {
- return true;
- }
- if (dfs(node.next) && node.val === root.val) {
- root = root.next;
- return true;
- }
- return false;
- };
- return dfs(head);
-}
diff --git a/lcci/02.07.Intersection of Two Linked Lists/README.md b/lcci/02.07.Intersection of Two Linked Lists/README.md
index fc268de03e30a..b6643ffd26e08 100644
--- a/lcci/02.07.Intersection of Two Linked Lists/README.md
+++ b/lcci/02.07.Intersection of Two Linked Lists/README.md
@@ -1,18 +1,41 @@
+---
+comments: true
+difficulty: 简单
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/02.07.Intersection%20of%20Two%20Linked%20Lists/README.md
+---
+
+
+
# [面试题 02.07. 链表相交](https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci)
[English Version](/lcci/02.07.Intersection%20of%20Two%20Linked%20Lists/README_EN.md)
## 题目描述
-
+
+
给定两个(单向)链表,判定它们是否相交并返回交点。请注意相交的定义基于节点的引用,而不是基于节点的值。换句话说,如果一个链表的第k个节点与另一个链表的第j个节点是同一节点(引用完全相同),则这两个链表相交。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null。
注意:
- 如果两个链表没有交点,返回
null
。 - 在返回结果后,两个链表仍须保持原有的结构。
- 可假定整个链表结构中没有循环。
- 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
+
+
## 解法
-### 方法一
+
+
+### 方法一:双指针
+
+我们使用两个指针 $a$, $b$ 分别指向两个链表 $headA$, $headB$。
+
+同时遍历链表,当 $a$ 到达链表 $headA$ 的末尾时,重新定位到链表 $headB$ 的头节点;当 $b$ 到达链表 $headB$ 的末尾时,重新定位到链表 $headA$ 的头节点。
+
+若两指针相遇,所指向的结点就是第一个公共节点。若没相遇,说明两链表无公共节点,此时两个指针都指向 `null`,返回其中一个即可。
+
+时间复杂度 $O(m+n)$,其中 $m$ 和 $n$ 分别是链表 $headA$ 和 $headB$ 的长度。空间复杂度 $O(1)$。
+#### Python3
+
```python
# Definition for singly-linked list.
# class ListNode:
@@ -23,13 +46,15 @@
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
- cur1, cur2 = headA, headB
- while cur1 != cur2:
- cur1 = headB if cur1 is None else cur1.next
- cur2 = headA if cur2 is None else cur2.next
- return cur1
+ a, b = headA, headB
+ while a != b:
+ a = a.next if a else headB
+ b = b.next if b else headA
+ return a
```
+#### Java
+
```java
/**
* Definition for singly-linked list.
@@ -44,16 +69,18 @@ class Solution:
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
- ListNode cur1 = headA, cur2 = headB;
- while (cur1 != cur2) {
- cur1 = cur1 == null ? headB : cur1.next;
- cur2 = cur2 == null ? headA : cur2.next;
+ ListNode a = headA, b = headB;
+ while (a != b) {
+ a = a == null ? headB : a.next;
+ b = b == null ? headA : b.next;
}
- return cur1;
+ return a;
}
}
```
+#### C++
+
```cpp
/**
* Definition for singly-linked list.
@@ -66,17 +93,18 @@ public class Solution {
class Solution {
public:
ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
- ListNode* cur1 = headA;
- ListNode* cur2 = headB;
- while (cur1 != cur2) {
- cur1 = cur1 ? cur1->next : headB;
- cur2 = cur2 ? cur2->next : headA;
+ ListNode *a = headA, *b = headB;
+ while (a != b) {
+ a = a ? a->next : headB;
+ b = b ? b->next : headA;
}
- return cur1;
+ return a;
}
};
```
+#### Go
+
```go
/**
* Definition for singly-linked list.
@@ -86,23 +114,51 @@ public:
* }
*/
func getIntersectionNode(headA, headB *ListNode) *ListNode {
- cur1, cur2 := headA, headB
- for cur1 != cur2 {
- if cur1 == nil {
- cur1 = headB
+ a, b := headA, headB
+ for a != b {
+ if a == nil {
+ a = headB
} else {
- cur1 = cur1.Next
+ a = a.Next
}
- if cur2 == nil {
- cur2 = headA
+ if b == nil {
+ b = headA
} else {
- cur2 = cur2.Next
+ b = b.Next
}
}
- return cur1
+ return a
+}
+```
+
+#### TypeScript
+
+```ts
+/**
+ * Definition for singly-linked list.
+ * class ListNode {
+ * val: number
+ * next: ListNode | null
+ * constructor(val?: number, next?: ListNode | null) {
+ * this.val = (val===undefined ? 0 : val)
+ * this.next = (next===undefined ? null : next)
+ * }
+ * }
+ */
+
+function getIntersectionNode(headA: ListNode | null, headB: ListNode | null): ListNode | null {
+ let a = headA;
+ let b = headB;
+ while (a != b) {
+ a = a ? a.next : headB;
+ b = b ? b.next : headA;
+ }
+ return a;
}
```
+#### JavaScript
+
```js
/**
* Definition for singly-linked list.
@@ -118,16 +174,46 @@ func getIntersectionNode(headA, headB *ListNode) *ListNode {
* @return {ListNode}
*/
var getIntersectionNode = function (headA, headB) {
- let cur1 = headA;
- let cur2 = headB;
- while (cur1 != cur2) {
- cur1 = cur1 ? cur1.next : headB;
- cur2 = cur2 ? cur2.next : headA;
+ let a = headA;
+ let b = headB;
+ while (a != b) {
+ a = a ? a.next : headB;
+ b = b ? b.next : headA;
}
- return cur1;
+ return a;
};
```
+#### Swift
+
+```swift
+/**
+ * Definition for singly-linked list.
+ * public class ListNode {
+ * public var val: Int
+ * public var next: ListNode?
+ * public init(_ val: Int) {
+ * self.val = val
+ * self.next = nil
+ * }
+ * }
+ */
+
+class Solution {
+ func getIntersectionNode(_ headA: ListNode?, _ headB: ListNode?) -> ListNode? {
+ var a = headA
+ var b = headB
+ while a !== b {
+ a = a == nil ? headB : a?.next
+ b = b == nil ? headA : b?.next
+ }
+ return a
+ }
+}
+```
+
-
+
+
+
diff --git a/lcci/02.07.Intersection of Two Linked Lists/README_EN.md b/lcci/02.07.Intersection of Two Linked Lists/README_EN.md
index bd2ee8ba86223..ac315b0efb893 100644
--- a/lcci/02.07.Intersection of Two Linked Lists/README_EN.md
+++ b/lcci/02.07.Intersection of Two Linked Lists/README_EN.md
@@ -1,9 +1,19 @@
+---
+comments: true
+difficulty: Easy
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/02.07.Intersection%20of%20Two%20Linked%20Lists/README_EN.md
+---
+
+
+
# [02.07. Intersection of Two Linked Lists](https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci)
[中文文档](/lcci/02.07.Intersection%20of%20Two%20Linked%20Lists/README.md)
## Description
+
+
Given two (singly) linked lists, determine if the two lists intersect. Return the inter secting node. Note that the intersection is defined based on reference, not value. That is, if the kth node of the first linked list is the exact same node (by reference) as the jth node of the second linked list, then they are intersecting.
Example 1:
@@ -45,12 +55,26 @@
- You may assume there are no cycles anywhere in the entire linked structure.
- Your code should preferably run in O(n) time and use only O(1) memory.
+
+
## Solutions
-### Solution 1
+
+
+### Solution 1: Two Pointers
+
+We use two pointers $a$ and $b$ to point to two linked lists $headA$ and $headB$ respectively.
+
+We traverse the linked lists simultaneously. When $a$ reaches the end of the linked list $headA$, it is repositioned to the head node of the linked list $headB$. When $b$ reaches the end of the linked list $headB$, it is repositioned to the head node of the linked list $headA$.
+
+If the two pointers meet, the node they point to is the first common node. If they don't meet, it means that the two linked lists have no common nodes. At this time, both pointers point to `null`, and we can return either one.
+
+The time complexity is $O(m+n)$, where $m$ and $n$ are the lengths of the linked lists $headA$ and $headB$ respectively. The space complexity is $O(1)$.
+#### Python3
+
```python
# Definition for singly-linked list.
# class ListNode:
@@ -61,13 +85,15 @@
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
- cur1, cur2 = headA, headB
- while cur1 != cur2:
- cur1 = headB if cur1 is None else cur1.next
- cur2 = headA if cur2 is None else cur2.next
- return cur1
+ a, b = headA, headB
+ while a != b:
+ a = a.next if a else headB
+ b = b.next if b else headA
+ return a
```
+#### Java
+
```java
/**
* Definition for singly-linked list.
@@ -82,16 +108,18 @@ class Solution:
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
- ListNode cur1 = headA, cur2 = headB;
- while (cur1 != cur2) {
- cur1 = cur1 == null ? headB : cur1.next;
- cur2 = cur2 == null ? headA : cur2.next;
+ ListNode a = headA, b = headB;
+ while (a != b) {
+ a = a == null ? headB : a.next;
+ b = b == null ? headA : b.next;
}
- return cur1;
+ return a;
}
}
```
+#### C++
+
```cpp
/**
* Definition for singly-linked list.
@@ -104,17 +132,18 @@ public class Solution {
class Solution {
public:
ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
- ListNode* cur1 = headA;
- ListNode* cur2 = headB;
- while (cur1 != cur2) {
- cur1 = cur1 ? cur1->next : headB;
- cur2 = cur2 ? cur2->next : headA;
+ ListNode *a = headA, *b = headB;
+ while (a != b) {
+ a = a ? a->next : headB;
+ b = b ? b->next : headA;
}
- return cur1;
+ return a;
}
};
```
+#### Go
+
```go
/**
* Definition for singly-linked list.
@@ -124,23 +153,51 @@ public:
* }
*/
func getIntersectionNode(headA, headB *ListNode) *ListNode {
- cur1, cur2 := headA, headB
- for cur1 != cur2 {
- if cur1 == nil {
- cur1 = headB
+ a, b := headA, headB
+ for a != b {
+ if a == nil {
+ a = headB
} else {
- cur1 = cur1.Next
+ a = a.Next
}
- if cur2 == nil {
- cur2 = headA
+ if b == nil {
+ b = headA
} else {
- cur2 = cur2.Next
+ b = b.Next
}
}
- return cur1
+ return a
+}
+```
+
+#### TypeScript
+
+```ts
+/**
+ * Definition for singly-linked list.
+ * class ListNode {
+ * val: number
+ * next: ListNode | null
+ * constructor(val?: number, next?: ListNode | null) {
+ * this.val = (val===undefined ? 0 : val)
+ * this.next = (next===undefined ? null : next)
+ * }
+ * }
+ */
+
+function getIntersectionNode(headA: ListNode | null, headB: ListNode | null): ListNode | null {
+ let a = headA;
+ let b = headB;
+ while (a != b) {
+ a = a ? a.next : headB;
+ b = b ? b.next : headA;
+ }
+ return a;
}
```
+#### JavaScript
+
```js
/**
* Definition for singly-linked list.
@@ -156,16 +213,46 @@ func getIntersectionNode(headA, headB *ListNode) *ListNode {
* @return {ListNode}
*/
var getIntersectionNode = function (headA, headB) {
- let cur1 = headA;
- let cur2 = headB;
- while (cur1 != cur2) {
- cur1 = cur1 ? cur1.next : headB;
- cur2 = cur2 ? cur2.next : headA;
+ let a = headA;
+ let b = headB;
+ while (a != b) {
+ a = a ? a.next : headB;
+ b = b ? b.next : headA;
}
- return cur1;
+ return a;
};
```
+#### Swift
+
+```swift
+/**
+ * Definition for singly-linked list.
+ * public class ListNode {
+ * public var val: Int
+ * public var next: ListNode?
+ * public init(_ val: Int) {
+ * self.val = val
+ * self.next = nil
+ * }
+ * }
+ */
+
+class Solution {
+ func getIntersectionNode(_ headA: ListNode?, _ headB: ListNode?) -> ListNode? {
+ var a = headA
+ var b = headB
+ while a !== b {
+ a = a == nil ? headB : a?.next
+ b = b == nil ? headA : b?.next
+ }
+ return a
+ }
+}
+```
+
-
+
+
+
diff --git a/lcci/02.07.Intersection of Two Linked Lists/Solution.cpp b/lcci/02.07.Intersection of Two Linked Lists/Solution.cpp
index 753db3cdd199c..6c4f6f2552d78 100644
--- a/lcci/02.07.Intersection of Two Linked Lists/Solution.cpp
+++ b/lcci/02.07.Intersection of Two Linked Lists/Solution.cpp
@@ -9,12 +9,11 @@
class Solution {
public:
ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
- ListNode* cur1 = headA;
- ListNode* cur2 = headB;
- while (cur1 != cur2) {
- cur1 = cur1 ? cur1->next : headB;
- cur2 = cur2 ? cur2->next : headA;
+ ListNode *a = headA, *b = headB;
+ while (a != b) {
+ a = a ? a->next : headB;
+ b = b ? b->next : headA;
}
- return cur1;
+ return a;
}
};
\ No newline at end of file
diff --git a/lcci/02.07.Intersection of Two Linked Lists/Solution.go b/lcci/02.07.Intersection of Two Linked Lists/Solution.go
index 217528bd00f5f..2cf2360642b64 100644
--- a/lcci/02.07.Intersection of Two Linked Lists/Solution.go
+++ b/lcci/02.07.Intersection of Two Linked Lists/Solution.go
@@ -6,18 +6,18 @@
* }
*/
func getIntersectionNode(headA, headB *ListNode) *ListNode {
- cur1, cur2 := headA, headB
- for cur1 != cur2 {
- if cur1 == nil {
- cur1 = headB
+ a, b := headA, headB
+ for a != b {
+ if a == nil {
+ a = headB
} else {
- cur1 = cur1.Next
+ a = a.Next
}
- if cur2 == nil {
- cur2 = headA
+ if b == nil {
+ b = headA
} else {
- cur2 = cur2.Next
+ b = b.Next
}
}
- return cur1
+ return a
}
\ No newline at end of file
diff --git a/lcci/02.07.Intersection of Two Linked Lists/Solution.java b/lcci/02.07.Intersection of Two Linked Lists/Solution.java
index ee4bb36e17936..9662eaaf538f7 100644
--- a/lcci/02.07.Intersection of Two Linked Lists/Solution.java
+++ b/lcci/02.07.Intersection of Two Linked Lists/Solution.java
@@ -11,11 +11,11 @@
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
- ListNode cur1 = headA, cur2 = headB;
- while (cur1 != cur2) {
- cur1 = cur1 == null ? headB : cur1.next;
- cur2 = cur2 == null ? headA : cur2.next;
+ ListNode a = headA, b = headB;
+ while (a != b) {
+ a = a == null ? headB : a.next;
+ b = b == null ? headA : b.next;
}
- return cur1;
+ return a;
}
}
\ No newline at end of file
diff --git a/lcci/02.07.Intersection of Two Linked Lists/Solution.js b/lcci/02.07.Intersection of Two Linked Lists/Solution.js
index d1ca97e8900a6..934643598feee 100644
--- a/lcci/02.07.Intersection of Two Linked Lists/Solution.js
+++ b/lcci/02.07.Intersection of Two Linked Lists/Solution.js
@@ -12,11 +12,11 @@
* @return {ListNode}
*/
var getIntersectionNode = function (headA, headB) {
- let cur1 = headA;
- let cur2 = headB;
- while (cur1 != cur2) {
- cur1 = cur1 ? cur1.next : headB;
- cur2 = cur2 ? cur2.next : headA;
+ let a = headA;
+ let b = headB;
+ while (a != b) {
+ a = a ? a.next : headB;
+ b = b ? b.next : headA;
}
- return cur1;
+ return a;
};
diff --git a/lcci/02.07.Intersection of Two Linked Lists/Solution.py b/lcci/02.07.Intersection of Two Linked Lists/Solution.py
index 000c74aac0285..bedd686dd2534 100644
--- a/lcci/02.07.Intersection of Two Linked Lists/Solution.py
+++ b/lcci/02.07.Intersection of Two Linked Lists/Solution.py
@@ -7,8 +7,8 @@
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
- cur1, cur2 = headA, headB
- while cur1 != cur2:
- cur1 = headB if cur1 is None else cur1.next
- cur2 = headA if cur2 is None else cur2.next
- return cur1
+ a, b = headA, headB
+ while a != b:
+ a = a.next if a else headB
+ b = b.next if b else headA
+ return a
diff --git a/lcci/02.07.Intersection of Two Linked Lists/Solution.swift b/lcci/02.07.Intersection of Two Linked Lists/Solution.swift
new file mode 100644
index 0000000000000..fa41e06ad2024
--- /dev/null
+++ b/lcci/02.07.Intersection of Two Linked Lists/Solution.swift
@@ -0,0 +1,23 @@
+/**
+ * Definition for singly-linked list.
+ * public class ListNode {
+ * public var val: Int
+ * public var next: ListNode?
+ * public init(_ val: Int) {
+ * self.val = val
+ * self.next = nil
+ * }
+ * }
+ */
+
+class Solution {
+ func getIntersectionNode(_ headA: ListNode?, _ headB: ListNode?) -> ListNode? {
+ var a = headA
+ var b = headB
+ while a !== b {
+ a = a == nil ? headB : a?.next
+ b = b == nil ? headA : b?.next
+ }
+ return a
+ }
+}
diff --git a/lcci/02.07.Intersection of Two Linked Lists/Solution.ts b/lcci/02.07.Intersection of Two Linked Lists/Solution.ts
new file mode 100644
index 0000000000000..d5321f905bf8c
--- /dev/null
+++ b/lcci/02.07.Intersection of Two Linked Lists/Solution.ts
@@ -0,0 +1,21 @@
+/**
+ * Definition for singly-linked list.
+ * class ListNode {
+ * val: number
+ * next: ListNode | null
+ * constructor(val?: number, next?: ListNode | null) {
+ * this.val = (val===undefined ? 0 : val)
+ * this.next = (next===undefined ? null : next)
+ * }
+ * }
+ */
+
+function getIntersectionNode(headA: ListNode | null, headB: ListNode | null): ListNode | null {
+ let a = headA;
+ let b = headB;
+ while (a != b) {
+ a = a ? a.next : headB;
+ b = b ? b.next : headA;
+ }
+ return a;
+}
diff --git a/lcci/02.08.Linked List Cycle/README.md b/lcci/02.08.Linked List Cycle/README.md
index 799505b036f3e..facce4bf87406 100644
--- a/lcci/02.08.Linked List Cycle/README.md
+++ b/lcci/02.08.Linked List Cycle/README.md
@@ -1,18 +1,51 @@
+---
+comments: true
+difficulty: 中等
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/02.08.Linked%20List%20Cycle/README.md
+---
+
+
+
# [面试题 02.08. 环路检测](https://leetcode.cn/problems/linked-list-cycle-lcci)
[English Version](/lcci/02.08.Linked%20List%20Cycle/README_EN.md)
## 题目描述
-
+
+
给定一个有环链表,实现一个算法返回环路的开头节点。
有环链表的定义:在链表中某个节点的next元素指向在它前面出现过的节点,则表明该链表存在环路。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。
进阶:
你是否可以不用额外空间解决此题?
+
+
## 解法
-### 方法一
+
+
+### 方法一:快慢指针
+
+我们先利用快慢指针判断链表是否有环,如果有环的话,快慢指针一定会相遇,且相遇的节点一定在环中。
+
+如果没有环,快指针会先到达链表尾部,直接返回 `null` 即可。
+
+如果有环,我们再定义一个答案指针 $ans$ 指向链表头部,然后让 $ans$ 和慢指针一起向前走,每次走一步,直到 $ans$ 和慢指针相遇,相遇的节点即为环的入口节点。
+
+为什么这样能找到环的入口节点呢?
+
+我们不妨假设链表头节点到环入口的距离为 $x$,环入口到相遇节点的距离为 $y$,相遇节点到环入口的距离为 $z$,那么慢指针走过的距离为 $x + y$,快指针走过的距离为 $x + y + k \times (y + z)$,其中 $k$ 是快指针在环中绕了 $k$ 圈。
+
+
+
+由于快指针速度是慢指针的 $2$ 倍,因此有 $2 \times (x + y) = x + y + k \times (y + z)$,可以推出 $x + y = k \times (y + z)$,即 $x = (k - 1) \times (y + z) + z$。
+
+也即是说,如果我们定义一个答案指针 $ans$ 指向链表头部,然后 $ans$ 和慢指针一起向前走,那么它们一定会在环入口相遇。
+
+时间复杂度 $O(n)$,其中 $n$ 是链表中节点的数目。空间复杂度 $O(1)$。
+#### Python3
+
```python
# Definition for singly-linked list.
# class ListNode:
@@ -22,20 +55,21 @@
class Solution:
- def detectCycle(self, head: ListNode) -> ListNode:
- slow = fast = head
- has_cycle = False
- while not has_cycle and fast and fast.next:
- slow, fast = slow.next, fast.next.next
- has_cycle = slow == fast
- if not has_cycle:
- return None
- p = head
- while p != slow:
- p, slow = p.next, slow.next
- return p
+ def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
+ fast = slow = head
+ while fast and fast.next:
+ slow = slow.next
+ fast = fast.next.next
+ if slow == fast:
+ ans = head
+ while ans != slow:
+ ans = ans.next
+ slow = slow.next
+ return ans
```
+#### Java
+
```java
/**
* Definition for singly-linked list.
@@ -50,26 +84,26 @@ class Solution:
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
- ListNode slow = head, fast = head;
- boolean hasCycle = false;
- while (!hasCycle && fast != null && fast.next != null) {
+ ListNode fast = head, slow = head;
+ while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
- hasCycle = slow == fast;
- }
- if (!hasCycle) {
- return null;
- }
- ListNode p = head;
- while (p != slow) {
- p = p.next;
- slow = slow.next;
+ if (slow == fast) {
+ ListNode ans = head;
+ while (ans != slow) {
+ ans = ans.next;
+ slow = slow.next;
+ }
+ return ans;
+ }
}
- return p;
+ return null;
}
}
```
+#### C++
+
```cpp
/**
* Definition for singly-linked list.
@@ -82,27 +116,27 @@ public class Solution {
class Solution {
public:
ListNode* detectCycle(ListNode* head) {
- ListNode* slow = head;
ListNode* fast = head;
- bool hasCycle = false;
- while (!hasCycle && fast && fast->next) {
+ ListNode* slow = head;
+ while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
- hasCycle = slow == fast;
+ if (slow == fast) {
+ ListNode* ans = head;
+ while (ans != slow) {
+ ans = ans->next;
+ slow = slow->next;
+ }
+ return ans;
+ }
}
- if (!hasCycle) {
- return nullptr;
- }
- ListNode* p = head;
- while (p != slow) {
- p = p->next;
- slow = slow->next;
- }
- return p;
+ return nullptr;
}
};
```
+#### Go
+
```go
/**
* Definition for singly-linked list.
@@ -112,23 +146,58 @@ public:
* }
*/
func detectCycle(head *ListNode) *ListNode {
- slow, fast := head, head
- hasCycle := false
- for !hasCycle && fast != nil && fast.Next != nil {
- slow, fast = slow.Next, fast.Next.Next
- hasCycle = slow == fast
+ fast, slow := head, head
+ for fast != nil && fast.Next != nil {
+ slow = slow.Next
+ fast = fast.Next.Next
+ if slow == fast {
+ ans := head
+ for ans != slow {
+ ans = ans.Next
+ slow = slow.Next
+ }
+ return ans
+ }
}
- if !hasCycle {
- return nil
- }
- p := head
- for p != slow {
- p, slow = p.Next, slow.Next
- }
- return p
+ return nil
+}
+```
+
+#### TypeScript
+
+```ts
+/**
+ * Definition for singly-linked list.
+ * class ListNode {
+ * val: number
+ * next: ListNode | null
+ * constructor(val?: number, next?: ListNode | null) {
+ * this.val = (val===undefined ? 0 : val)
+ * this.next = (next===undefined ? null : next)
+ * }
+ * }
+ */
+
+function detectCycle(head: ListNode | null): ListNode | null {
+ let [slow, fast] = [head, head];
+ while (fast && fast.next) {
+ slow = slow.next;
+ fast = fast.next.next;
+ if (slow === fast) {
+ let ans = head;
+ while (ans !== slow) {
+ ans = ans.next;
+ slow = slow.next;
+ }
+ return ans;
+ }
+ }
+ return null;
}
```
+#### JavaScript
+
```js
/**
* Definition for singly-linked list.
@@ -143,26 +212,61 @@ func detectCycle(head *ListNode) *ListNode {
* @return {ListNode}
*/
var detectCycle = function (head) {
- let slow = head;
- let fast = head;
- let hasCycle = false;
- while (!hasCycle && fast && fast.next) {
+ let [slow, fast] = [head, head];
+ while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
- hasCycle = slow == fast;
- }
- if (!hasCycle) {
- return null;
- }
- let p = head;
- while (p != slow) {
- p = p.next;
- slow = slow.next;
+ if (slow === fast) {
+ let ans = head;
+ while (ans !== slow) {
+ ans = ans.next;
+ slow = slow.next;
+ }
+ return ans;
+ }
}
- return p;
+ return null;
};
```
+#### Swift
+
+```swift
+/*
+* public class ListNode {
+* var val: Int
+* var next: ListNode?
+* init(_ x: Int) {
+* self.val = x
+* self.next = nil
+* }
+* }
+*/
+
+class Solution {
+ func detectCycle(_ head: ListNode?) -> ListNode? {
+ var slow = head
+ var fast = head
+
+ while fast != nil && fast?.next != nil {
+ slow = slow?.next
+ fast = fast?.next?.next
+ if slow === fast {
+ var ans = head
+ while ans !== slow {
+ ans = ans?.next
+ slow = slow?.next
+ }
+ return ans
+ }
+ }
+ return nil
+ }
+}
+```
+
-
+
+
+
diff --git a/lcci/02.08.Linked List Cycle/README_EN.md b/lcci/02.08.Linked List Cycle/README_EN.md
index b2d71ab97c1dd..575492b63d0a3 100644
--- a/lcci/02.08.Linked List Cycle/README_EN.md
+++ b/lcci/02.08.Linked List Cycle/README_EN.md
@@ -1,9 +1,19 @@
+---
+comments: true
+difficulty: Medium
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/02.08.Linked%20List%20Cycle/README_EN.md
+---
+
+
+
# [02.08. Linked List Cycle](https://leetcode.cn/problems/linked-list-cycle-lcci)
[中文文档](/lcci/02.08.Linked%20List%20Cycle/README.md)
## Description
+
+
Given a circular linked list, implement an algorithm that returns the node at the beginning of the loop.
Circular linked list: A (corrupt) linked list in which a node's next pointer points to an earlier node, so as to make a loop in the linked list.
@@ -36,12 +46,36 @@
Can you solve it without using additional space?
+
+
## Solutions
-### Solution 1
+
+
+### Solution 1: Two Pointers
+
+We first use the fast and slow pointers to judge whether the linked list has a ring. If there is a ring, the fast and slow pointers will definitely meet, and the meeting node must be in the ring.
+
+If there is no ring, the fast pointer will reach the tail of the linked list first, and return `null` directly.
+
+If there is a ring, we then define an answer pointer $ans$ to point to the head of the linked list, and then let $ans$ and the slow pointer move forward together, moving one step at a time, until $ans$ and the slow pointer meet, and the meeting node is the ring entrance node.
+
+Why can this find the entrance node of the ring?
+
+Let's assume that the distance from the head node of the linked list to the entrance of the ring is $x$, the distance from the entrance of the ring to the meeting node is $y$, and the distance from the meeting node to the entrance of the ring is $z$. Then the distance traveled by the slow pointer is $x + y$, and the distance traveled by the fast pointer is $x + y + k \times (y + z)$, where $k$ is the number of times the fast pointer goes around the ring.
+
+
+
+Because the speed of the fast pointer is twice that of the slow pointer, it is $2 \times (x + y) = x + y + k \times (y + z)$, which can be deduced that $x + y = k \times (y + z)$, that is $x = (k - 1) \times (y + z) + z$.
+
+That is to say, if we define an answer pointer $ans$ to point to the head of the linked list, and the $ans$ and the slow pointer move forward together, they will definitely meet at the ring entrance.
+
+The time complexity is $O(n)$, where $n$ is the number of nodes in the linked list. The space complexity is $O(1)$.
+#### Python3
+
```python
# Definition for singly-linked list.
# class ListNode:
@@ -51,20 +85,21 @@ Can you solve it without using additional space?
class Solution:
- def detectCycle(self, head: ListNode) -> ListNode:
- slow = fast = head
- has_cycle = False
- while not has_cycle and fast and fast.next:
- slow, fast = slow.next, fast.next.next
- has_cycle = slow == fast
- if not has_cycle:
- return None
- p = head
- while p != slow:
- p, slow = p.next, slow.next
- return p
+ def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
+ fast = slow = head
+ while fast and fast.next:
+ slow = slow.next
+ fast = fast.next.next
+ if slow == fast:
+ ans = head
+ while ans != slow:
+ ans = ans.next
+ slow = slow.next
+ return ans
```
+#### Java
+
```java
/**
* Definition for singly-linked list.
@@ -79,26 +114,26 @@ class Solution:
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
- ListNode slow = head, fast = head;
- boolean hasCycle = false;
- while (!hasCycle && fast != null && fast.next != null) {
+ ListNode fast = head, slow = head;
+ while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
- hasCycle = slow == fast;
- }
- if (!hasCycle) {
- return null;
- }
- ListNode p = head;
- while (p != slow) {
- p = p.next;
- slow = slow.next;
+ if (slow == fast) {
+ ListNode ans = head;
+ while (ans != slow) {
+ ans = ans.next;
+ slow = slow.next;
+ }
+ return ans;
+ }
}
- return p;
+ return null;
}
}
```
+#### C++
+
```cpp
/**
* Definition for singly-linked list.
@@ -111,27 +146,27 @@ public class Solution {
class Solution {
public:
ListNode* detectCycle(ListNode* head) {
- ListNode* slow = head;
ListNode* fast = head;
- bool hasCycle = false;
- while (!hasCycle && fast && fast->next) {
+ ListNode* slow = head;
+ while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
- hasCycle = slow == fast;
+ if (slow == fast) {
+ ListNode* ans = head;
+ while (ans != slow) {
+ ans = ans->next;
+ slow = slow->next;
+ }
+ return ans;
+ }
}
- if (!hasCycle) {
- return nullptr;
- }
- ListNode* p = head;
- while (p != slow) {
- p = p->next;
- slow = slow->next;
- }
- return p;
+ return nullptr;
}
};
```
+#### Go
+
```go
/**
* Definition for singly-linked list.
@@ -141,23 +176,58 @@ public:
* }
*/
func detectCycle(head *ListNode) *ListNode {
- slow, fast := head, head
- hasCycle := false
- for !hasCycle && fast != nil && fast.Next != nil {
- slow, fast = slow.Next, fast.Next.Next
- hasCycle = slow == fast
+ fast, slow := head, head
+ for fast != nil && fast.Next != nil {
+ slow = slow.Next
+ fast = fast.Next.Next
+ if slow == fast {
+ ans := head
+ for ans != slow {
+ ans = ans.Next
+ slow = slow.Next
+ }
+ return ans
+ }
}
- if !hasCycle {
- return nil
- }
- p := head
- for p != slow {
- p, slow = p.Next, slow.Next
- }
- return p
+ return nil
+}
+```
+
+#### TypeScript
+
+```ts
+/**
+ * Definition for singly-linked list.
+ * class ListNode {
+ * val: number
+ * next: ListNode | null
+ * constructor(val?: number, next?: ListNode | null) {
+ * this.val = (val===undefined ? 0 : val)
+ * this.next = (next===undefined ? null : next)
+ * }
+ * }
+ */
+
+function detectCycle(head: ListNode | null): ListNode | null {
+ let [slow, fast] = [head, head];
+ while (fast && fast.next) {
+ slow = slow.next;
+ fast = fast.next.next;
+ if (slow === fast) {
+ let ans = head;
+ while (ans !== slow) {
+ ans = ans.next;
+ slow = slow.next;
+ }
+ return ans;
+ }
+ }
+ return null;
}
```
+#### JavaScript
+
```js
/**
* Definition for singly-linked list.
@@ -172,26 +242,61 @@ func detectCycle(head *ListNode) *ListNode {
* @return {ListNode}
*/
var detectCycle = function (head) {
- let slow = head;
- let fast = head;
- let hasCycle = false;
- while (!hasCycle && fast && fast.next) {
+ let [slow, fast] = [head, head];
+ while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
- hasCycle = slow == fast;
- }
- if (!hasCycle) {
- return null;
- }
- let p = head;
- while (p != slow) {
- p = p.next;
- slow = slow.next;
+ if (slow === fast) {
+ let ans = head;
+ while (ans !== slow) {
+ ans = ans.next;
+ slow = slow.next;
+ }
+ return ans;
+ }
}
- return p;
+ return null;
};
```
+#### Swift
+
+```swift
+/*
+* public class ListNode {
+* var val: Int
+* var next: ListNode?
+* init(_ x: Int) {
+* self.val = x
+* self.next = nil
+* }
+* }
+*/
+
+class Solution {
+ func detectCycle(_ head: ListNode?) -> ListNode? {
+ var slow = head
+ var fast = head
+
+ while fast != nil && fast?.next != nil {
+ slow = slow?.next
+ fast = fast?.next?.next
+ if slow === fast {
+ var ans = head
+ while ans !== slow {
+ ans = ans?.next
+ slow = slow?.next
+ }
+ return ans
+ }
+ }
+ return nil
+ }
+}
+```
+
-
+
+
+
diff --git a/lcci/02.08.Linked List Cycle/Solution.cpp b/lcci/02.08.Linked List Cycle/Solution.cpp
index 890916dbc2485..480c200cce75d 100644
--- a/lcci/02.08.Linked List Cycle/Solution.cpp
+++ b/lcci/02.08.Linked List Cycle/Solution.cpp
@@ -9,22 +9,20 @@
class Solution {
public:
ListNode* detectCycle(ListNode* head) {
- ListNode* slow = head;
ListNode* fast = head;
- bool hasCycle = false;
- while (!hasCycle && fast && fast->next) {
+ ListNode* slow = head;
+ while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
- hasCycle = slow == fast;
- }
- if (!hasCycle) {
- return nullptr;
- }
- ListNode* p = head;
- while (p != slow) {
- p = p->next;
- slow = slow->next;
+ if (slow == fast) {
+ ListNode* ans = head;
+ while (ans != slow) {
+ ans = ans->next;
+ slow = slow->next;
+ }
+ return ans;
+ }
}
- return p;
+ return nullptr;
}
};
\ No newline at end of file
diff --git a/lcci/02.08.Linked List Cycle/Solution.go b/lcci/02.08.Linked List Cycle/Solution.go
index 29cb7c3eb5848..2a55341dd8464 100644
--- a/lcci/02.08.Linked List Cycle/Solution.go
+++ b/lcci/02.08.Linked List Cycle/Solution.go
@@ -6,18 +6,18 @@
* }
*/
func detectCycle(head *ListNode) *ListNode {
- slow, fast := head, head
- hasCycle := false
- for !hasCycle && fast != nil && fast.Next != nil {
- slow, fast = slow.Next, fast.Next.Next
- hasCycle = slow == fast
+ fast, slow := head, head
+ for fast != nil && fast.Next != nil {
+ slow = slow.Next
+ fast = fast.Next.Next
+ if slow == fast {
+ ans := head
+ for ans != slow {
+ ans = ans.Next
+ slow = slow.Next
+ }
+ return ans
+ }
}
- if !hasCycle {
- return nil
- }
- p := head
- for p != slow {
- p, slow = p.Next, slow.Next
- }
- return p
+ return nil
}
\ No newline at end of file
diff --git a/lcci/02.08.Linked List Cycle/Solution.java b/lcci/02.08.Linked List Cycle/Solution.java
index 95282d17fb34f..d97ce63041d60 100644
--- a/lcci/02.08.Linked List Cycle/Solution.java
+++ b/lcci/02.08.Linked List Cycle/Solution.java
@@ -11,21 +11,19 @@
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
- ListNode slow = head, fast = head;
- boolean hasCycle = false;
- while (!hasCycle && fast != null && fast.next != null) {
+ ListNode fast = head, slow = head;
+ while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
- hasCycle = slow == fast;
+ if (slow == fast) {
+ ListNode ans = head;
+ while (ans != slow) {
+ ans = ans.next;
+ slow = slow.next;
+ }
+ return ans;
+ }
}
- if (!hasCycle) {
- return null;
- }
- ListNode p = head;
- while (p != slow) {
- p = p.next;
- slow = slow.next;
- }
- return p;
+ return null;
}
}
\ No newline at end of file
diff --git a/lcci/02.08.Linked List Cycle/Solution.js b/lcci/02.08.Linked List Cycle/Solution.js
index 409dfa46a3ed7..7546639d0047a 100644
--- a/lcci/02.08.Linked List Cycle/Solution.js
+++ b/lcci/02.08.Linked List Cycle/Solution.js
@@ -11,21 +11,18 @@
* @return {ListNode}
*/
var detectCycle = function (head) {
- let slow = head;
- let fast = head;
- let hasCycle = false;
- while (!hasCycle && fast && fast.next) {
+ let [slow, fast] = [head, head];
+ while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
- hasCycle = slow == fast;
+ if (slow === fast) {
+ let ans = head;
+ while (ans !== slow) {
+ ans = ans.next;
+ slow = slow.next;
+ }
+ return ans;
+ }
}
- if (!hasCycle) {
- return null;
- }
- let p = head;
- while (p != slow) {
- p = p.next;
- slow = slow.next;
- }
- return p;
+ return null;
};
diff --git a/lcci/02.08.Linked List Cycle/Solution.py b/lcci/02.08.Linked List Cycle/Solution.py
index 381618f41c2d1..e28f848a4834c 100644
--- a/lcci/02.08.Linked List Cycle/Solution.py
+++ b/lcci/02.08.Linked List Cycle/Solution.py
@@ -6,15 +6,14 @@
class Solution:
- def detectCycle(self, head: ListNode) -> ListNode:
- slow = fast = head
- has_cycle = False
- while not has_cycle and fast and fast.next:
- slow, fast = slow.next, fast.next.next
- has_cycle = slow == fast
- if not has_cycle:
- return None
- p = head
- while p != slow:
- p, slow = p.next, slow.next
- return p
+ def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
+ fast = slow = head
+ while fast and fast.next:
+ slow = slow.next
+ fast = fast.next.next
+ if slow == fast:
+ ans = head
+ while ans != slow:
+ ans = ans.next
+ slow = slow.next
+ return ans
diff --git a/lcci/02.08.Linked List Cycle/Solution.swift b/lcci/02.08.Linked List Cycle/Solution.swift
new file mode 100644
index 0000000000000..fbed4eae0d4c9
--- /dev/null
+++ b/lcci/02.08.Linked List Cycle/Solution.swift
@@ -0,0 +1,31 @@
+/*
+* public class ListNode {
+* var val: Int
+* var next: ListNode?
+* init(_ x: Int) {
+* self.val = x
+* self.next = nil
+* }
+* }
+*/
+
+class Solution {
+ func detectCycle(_ head: ListNode?) -> ListNode? {
+ var slow = head
+ var fast = head
+
+ while fast != nil && fast?.next != nil {
+ slow = slow?.next
+ fast = fast?.next?.next
+ if slow === fast {
+ var ans = head
+ while ans !== slow {
+ ans = ans?.next
+ slow = slow?.next
+ }
+ return ans
+ }
+ }
+ return nil
+ }
+}
diff --git a/lcci/02.08.Linked List Cycle/Solution.ts b/lcci/02.08.Linked List Cycle/Solution.ts
new file mode 100644
index 0000000000000..1919f3cb375a8
--- /dev/null
+++ b/lcci/02.08.Linked List Cycle/Solution.ts
@@ -0,0 +1,28 @@
+/**
+ * Definition for singly-linked list.
+ * class ListNode {
+ * val: number
+ * next: ListNode | null
+ * constructor(val?: number, next?: ListNode | null) {
+ * this.val = (val===undefined ? 0 : val)
+ * this.next = (next===undefined ? null : next)
+ * }
+ * }
+ */
+
+function detectCycle(head: ListNode | null): ListNode | null {
+ let [slow, fast] = [head, head];
+ while (fast && fast.next) {
+ slow = slow.next;
+ fast = fast.next.next;
+ if (slow === fast) {
+ let ans = head;
+ while (ans !== slow) {
+ ans = ans.next;
+ slow = slow.next;
+ }
+ return ans;
+ }
+ }
+ return null;
+}
diff --git a/lcci/03.01.Three in One/README.md b/lcci/03.01.Three in One/README.md
index 32a5e66fbc233..3a2604f22caf0 100644
--- a/lcci/03.01.Three in One/README.md
+++ b/lcci/03.01.Three in One/README.md
@@ -1,10 +1,19 @@
+---
+comments: true
+difficulty: 简单
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/03.01.Three%20in%20One/README.md
+---
+
+
+
# [面试题 03.01. 三合一](https://leetcode.cn/problems/three-in-one-lcci)
[English Version](/lcci/03.01.Three%20in%20One/README_EN.md)
## 题目描述
-
+
+
三合一。描述如何只用一个数组来实现三个栈。
你应该实现push(stackNum, value)
、pop(stackNum)
、isEmpty(stackNum)
、peek(stackNum)
方法。stackNum
表示栈下标,value
表示压入的值。
@@ -30,30 +39,55 @@
[null, null, null, null, 2, 1, -1, -1]
+
+
## 解法
-### 方法一
+
+
+### 方法一:数组模拟
+
+我们使用一个变量 $cap$ 来表示每个栈的大小,使用一个长度为 $3 \times \textit{cap} + 3$ 的数组 $stk$ 来模拟三个栈,数组的前 $3 \times \textit{cap}$ 个元素用来存储栈的元素,数组的后三个元素用来存储每个栈的元素个数。
+
+对于 `push` 操作,我们首先判断栈是否已满,如果未满,则将元素压入栈中,并更新栈的元素个数。
+
+对于 `pop` 操作,我们首先判断栈是否为空,如果不为空,则更新栈的元素个数,并返回栈顶元素。
+
+对于 `peek` 操作,我们首先判断栈是否为空,如果不为空,则返回栈顶元素。
+
+对于 `isEmpty` 操作,我们直接判断栈是否为空即可。对于栈 $i$,我们只需要判断 $stk[\textit{cap} \times 3 + i]$ 是否为 $0$ 即可。
+
+时间复杂度上,每个操作的时间复杂度均为 $O(1)$。空间复杂度为 $O(\textit{cap})$,其中 $\textit{cap}$ 为栈的大小。
+#### Python3
+
```python
class TripleInOne:
+
def __init__(self, stackSize: int):
- self._capacity = stackSize
- self._s = [[], [], []]
+ self.cap = stackSize
+ self.stk = [0] * (self.cap * 3 + 3)
def push(self, stackNum: int, value: int) -> None:
- if len(self._s[stackNum]) < self._capacity:
- self._s[stackNum].append(value)
+ if self.stk[self.cap * 3 + stackNum] < self.cap:
+ self.stk[self.cap * stackNum + self.stk[self.cap * 3 + stackNum]] = value
+ self.stk[self.cap * 3 + stackNum] += 1
def pop(self, stackNum: int) -> int:
- return -1 if self.isEmpty(stackNum) else self._s[stackNum].pop()
+ if self.isEmpty(stackNum):
+ return -1
+ self.stk[self.cap * 3 + stackNum] -= 1
+ return self.stk[self.cap * stackNum + self.stk[self.cap * 3 + stackNum]]
def peek(self, stackNum: int) -> int:
- return -1 if self.isEmpty(stackNum) else self._s[stackNum][-1]
+ if self.isEmpty(stackNum):
+ return -1
+ return self.stk[self.cap * stackNum + self.stk[self.cap * 3 + stackNum] - 1]
def isEmpty(self, stackNum: int) -> bool:
- return len(self._s[stackNum]) == 0
+ return self.stk[self.cap * 3 + stackNum] == 0
# Your TripleInOne object will be instantiated and called as such:
@@ -64,20 +98,22 @@ class TripleInOne:
# param_4 = obj.isEmpty(stackNum)
```
+#### Java
+
```java
class TripleInOne {
- private int[] s;
- private int capacity;
+ private int cap;
+ private int[] stk;
public TripleInOne(int stackSize) {
- s = new int[stackSize * 3 + 3];
- capacity = stackSize;
+ cap = stackSize;
+ stk = new int[cap * 3 + 3];
}
public void push(int stackNum, int value) {
- if (s[stackNum + 3 * capacity] < capacity) {
- s[s[stackNum + 3 * capacity] * 3 + stackNum] = value;
- ++s[stackNum + 3 * capacity];
+ if (stk[cap * 3 + stackNum] < cap) {
+ stk[cap * stackNum + stk[cap * 3 + stackNum]] = value;
+ ++stk[cap * 3 + stackNum];
}
}
@@ -85,16 +121,16 @@ class TripleInOne {
if (isEmpty(stackNum)) {
return -1;
}
- --s[stackNum + 3 * capacity];
- return s[s[stackNum + 3 * capacity] * 3 + stackNum];
+ --stk[cap * 3 + stackNum];
+ return stk[cap * stackNum + stk[cap * 3 + stackNum]];
}
public int peek(int stackNum) {
- return isEmpty(stackNum) ? -1 : s[(s[stackNum + 3 * capacity] - 1) * 3 + stackNum];
+ return isEmpty(stackNum) ? -1 : stk[cap * stackNum + stk[cap * 3 + stackNum] - 1];
}
public boolean isEmpty(int stackNum) {
- return s[stackNum + 3 * capacity] == 0;
+ return stk[cap * 3 + stackNum] == 0;
}
}
@@ -108,54 +144,90 @@ class TripleInOne {
*/
```
+#### C++
+
+```cpp
+class TripleInOne {
+public:
+ TripleInOne(int stackSize) {
+ cap = stackSize;
+ stk.resize(cap * 3 + 3);
+ }
+
+ void push(int stackNum, int value) {
+ if (stk[cap * 3 + stackNum] < cap) {
+ stk[cap * stackNum + stk[cap * 3 + stackNum]] = value;
+ ++stk[cap * 3 + stackNum];
+ }
+ }
+
+ int pop(int stackNum) {
+ if (isEmpty(stackNum)) {
+ return -1;
+ }
+ --stk[cap * 3 + stackNum];
+ return stk[cap * stackNum + stk[cap * 3 + stackNum]];
+ }
+
+ int peek(int stackNum) {
+ return isEmpty(stackNum) ? -1 : stk[cap * stackNum + stk[cap * 3 + stackNum] - 1];
+ }
+
+ bool isEmpty(int stackNum) {
+ return stk[cap * 3 + stackNum] == 0;
+ }
+
+private:
+ int cap;
+ vector stk;
+};
+
+/**
+ * Your TripleInOne object will be instantiated and called as such:
+ * TripleInOne* obj = new TripleInOne(stackSize);
+ * obj->push(stackNum,value);
+ * int param_2 = obj->pop(stackNum);
+ * int param_3 = obj->peek(stackNum);
+ * bool param_4 = obj->isEmpty(stackNum);
+ */
+```
+
+#### Go
+
```go
type TripleInOne struct {
- data []int
- offset [3]int
- stackSize int
+ cap int
+ stk []int
}
func Constructor(stackSize int) TripleInOne {
- total := stackSize * 3
- data := make([]int, total)
- offset := [3]int{}
- for i := 0; i < 3; i++ {
- offset[i] = i * stackSize
- }
- return TripleInOne{
- data: data,
- offset: offset,
- stackSize: stackSize,
- }
+ return TripleInOne{stackSize, make([]int, stackSize*3+3)}
}
func (this *TripleInOne) Push(stackNum int, value int) {
- i := this.offset[stackNum]
- if i < (stackNum+1)*this.stackSize {
- this.data[i] = value
- this.offset[stackNum]++
+ if this.stk[this.cap*3+stackNum] < this.cap {
+ this.stk[this.cap*stackNum+this.stk[this.cap*3+stackNum]] = value
+ this.stk[this.cap*3+stackNum]++
}
}
func (this *TripleInOne) Pop(stackNum int) int {
- i := this.offset[stackNum]
- if i == stackNum*this.stackSize {
+ if this.IsEmpty(stackNum) {
return -1
}
- this.offset[stackNum]--
- return this.data[i-1]
+ this.stk[this.cap*3+stackNum]--
+ return this.stk[this.cap*stackNum+this.stk[this.cap*3+stackNum]]
}
func (this *TripleInOne) Peek(stackNum int) int {
- i := this.offset[stackNum]
- if i == stackNum*this.stackSize {
+ if this.IsEmpty(stackNum) {
return -1
}
- return this.data[i-1]
+ return this.stk[this.cap*stackNum+this.stk[this.cap*3+stackNum]-1]
}
func (this *TripleInOne) IsEmpty(stackNum int) bool {
- return this.offset[stackNum] == stackNum*this.stackSize
+ return this.stk[this.cap*3+stackNum] == 0
}
/**
@@ -168,6 +240,106 @@ func (this *TripleInOne) IsEmpty(stackNum int) bool {
*/
```
+#### TypeScript
+
+```ts
+class TripleInOne {
+ private cap: number;
+ private stk: number[];
+
+ constructor(stackSize: number) {
+ this.cap = stackSize;
+ this.stk = Array(stackSize * 3 + 3).fill(0);
+ }
+
+ push(stackNum: number, value: number): void {
+ if (this.stk[this.cap * 3 + stackNum] < this.cap) {
+ this.stk[this.cap * stackNum + this.stk[this.cap * 3 + stackNum]] = value;
+ this.stk[this.cap * 3 + stackNum]++;
+ }
+ }
+
+ pop(stackNum: number): number {
+ if (this.isEmpty(stackNum)) {
+ return -1;
+ }
+ this.stk[this.cap * 3 + stackNum]--;
+ return this.stk[this.cap * stackNum + this.stk[this.cap * 3 + stackNum]];
+ }
+
+ peek(stackNum: number): number {
+ if (this.isEmpty(stackNum)) {
+ return -1;
+ }
+ return this.stk[this.cap * stackNum + this.stk[this.cap * 3 + stackNum] - 1];
+ }
+
+ isEmpty(stackNum: number): boolean {
+ return this.stk[this.cap * 3 + stackNum] === 0;
+ }
+}
+
+/**
+ * Your TripleInOne object will be instantiated and called as such:
+ * var obj = new TripleInOne(stackSize)
+ * obj.push(stackNum,value)
+ * var param_2 = obj.pop(stackNum)
+ * var param_3 = obj.peek(stackNum)
+ * var param_4 = obj.isEmpty(stackNum)
+ */
+```
+
+#### Swift
+
+```swift
+class TripleInOne {
+ private var cap: Int
+ private var stk: [Int]
+
+ init(_ stackSize: Int) {
+ self.cap = stackSize
+ self.stk = [Int](repeating: 0, count: cap * 3 + 3)
+ }
+
+ func push(_ stackNum: Int, _ value: Int) {
+ if stk[cap * 3 + stackNum] < cap {
+ stk[cap * stackNum + stk[cap * 3 + stackNum]] = value
+ stk[cap * 3 + stackNum] += 1
+ }
+ }
+
+ func pop(_ stackNum: Int) -> Int {
+ if isEmpty(stackNum) {
+ return -1
+ }
+ stk[cap * 3 + stackNum] -= 1
+ return stk[cap * stackNum + stk[cap * 3 + stackNum]]
+ }
+
+ func peek(_ stackNum: Int) -> Int {
+ if isEmpty(stackNum) {
+ return -1
+ }
+ return stk[cap * stackNum + stk[cap * 3 + stackNum] - 1]
+ }
+
+ func isEmpty(_ stackNum: Int) -> Bool {
+ return stk[cap * 3 + stackNum] == 0
+ }
+}
+
+/**
+ * Your TripleInOne object will be instantiated and called as such:
+ * let obj = TripleInOne(stackSize)
+ * obj.push(stackNum,value)
+ * let param_2 = obj.pop(stackNum)
+ * let param_3 = obj.peek(stackNum)
+ * let param_4 = obj.isEmpty(stackNum)
+ */
+```
+
-
+
+
+
diff --git a/lcci/03.01.Three in One/README_EN.md b/lcci/03.01.Three in One/README_EN.md
index ec7d209a4dbab..e3a4801150493 100644
--- a/lcci/03.01.Three in One/README_EN.md
+++ b/lcci/03.01.Three in One/README_EN.md
@@ -1,9 +1,19 @@
+---
+comments: true
+difficulty: Easy
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/03.01.Three%20in%20One/README_EN.md
+---
+
+
+
# [03.01. Three in One](https://leetcode.cn/problems/three-in-one-lcci)
[中文文档](/lcci/03.01.Three%20in%20One/README.md)
## Description
+
+
Describe how you could use a single array to implement three stacks.
Yout should implement push(stackNum, value)
、pop(stackNum)
、isEmpty(stackNum)
、peek(stackNum)
methods. stackNum
is the index of the stack. value
is the value that pushed to the stack.
@@ -44,30 +54,55 @@
+
+
## Solutions
-### Solution 1
+
+
+### Solution 1: Array Simulation
+
+We use a variable $cap$ to represent the size of each stack, and use an array $stk$ of length $3 \times \textit{cap} + 3$ to simulate three stacks. The first $3 \times \textit{cap}$ elements of the array are used to store the elements of the stack, and the last three elements are used to store the number of elements in each stack.
+
+For the `push` operation, we first check whether the stack is full. If it is not full, we push the element into the stack and update the number of elements in the stack.
+
+For the `pop` operation, we first check whether the stack is empty. If it is not empty, we update the number of elements in the stack and return the top element of the stack.
+
+For the `peek` operation, we first check whether the stack is empty. If it is not empty, we return the top element of the stack.
+
+For the `isEmpty` operation, we directly check whether the stack is empty. For stack $i$, we only need to check whether $stk[\textit{cap} \times 3 + i]$ is $0$.
+
+In terms of time complexity, the time complexity of each operation is $O(1)$. The space complexity is $O(\textit{cap})$, where $\textit{cap}$ is the size of the stack.
+#### Python3
+
```python
class TripleInOne:
+
def __init__(self, stackSize: int):
- self._capacity = stackSize
- self._s = [[], [], []]
+ self.cap = stackSize
+ self.stk = [0] * (self.cap * 3 + 3)
def push(self, stackNum: int, value: int) -> None:
- if len(self._s[stackNum]) < self._capacity:
- self._s[stackNum].append(value)
+ if self.stk[self.cap * 3 + stackNum] < self.cap:
+ self.stk[self.cap * stackNum + self.stk[self.cap * 3 + stackNum]] = value
+ self.stk[self.cap * 3 + stackNum] += 1
def pop(self, stackNum: int) -> int:
- return -1 if self.isEmpty(stackNum) else self._s[stackNum].pop()
+ if self.isEmpty(stackNum):
+ return -1
+ self.stk[self.cap * 3 + stackNum] -= 1
+ return self.stk[self.cap * stackNum + self.stk[self.cap * 3 + stackNum]]
def peek(self, stackNum: int) -> int:
- return -1 if self.isEmpty(stackNum) else self._s[stackNum][-1]
+ if self.isEmpty(stackNum):
+ return -1
+ return self.stk[self.cap * stackNum + self.stk[self.cap * 3 + stackNum] - 1]
def isEmpty(self, stackNum: int) -> bool:
- return len(self._s[stackNum]) == 0
+ return self.stk[self.cap * 3 + stackNum] == 0
# Your TripleInOne object will be instantiated and called as such:
@@ -78,20 +113,22 @@ class TripleInOne:
# param_4 = obj.isEmpty(stackNum)
```
+#### Java
+
```java
class TripleInOne {
- private int[] s;
- private int capacity;
+ private int cap;
+ private int[] stk;
public TripleInOne(int stackSize) {
- s = new int[stackSize * 3 + 3];
- capacity = stackSize;
+ cap = stackSize;
+ stk = new int[cap * 3 + 3];
}
public void push(int stackNum, int value) {
- if (s[stackNum + 3 * capacity] < capacity) {
- s[s[stackNum + 3 * capacity] * 3 + stackNum] = value;
- ++s[stackNum + 3 * capacity];
+ if (stk[cap * 3 + stackNum] < cap) {
+ stk[cap * stackNum + stk[cap * 3 + stackNum]] = value;
+ ++stk[cap * 3 + stackNum];
}
}
@@ -99,16 +136,16 @@ class TripleInOne {
if (isEmpty(stackNum)) {
return -1;
}
- --s[stackNum + 3 * capacity];
- return s[s[stackNum + 3 * capacity] * 3 + stackNum];
+ --stk[cap * 3 + stackNum];
+ return stk[cap * stackNum + stk[cap * 3 + stackNum]];
}
public int peek(int stackNum) {
- return isEmpty(stackNum) ? -1 : s[(s[stackNum + 3 * capacity] - 1) * 3 + stackNum];
+ return isEmpty(stackNum) ? -1 : stk[cap * stackNum + stk[cap * 3 + stackNum] - 1];
}
public boolean isEmpty(int stackNum) {
- return s[stackNum + 3 * capacity] == 0;
+ return stk[cap * 3 + stackNum] == 0;
}
}
@@ -122,54 +159,90 @@ class TripleInOne {
*/
```
+#### C++
+
+```cpp
+class TripleInOne {
+public:
+ TripleInOne(int stackSize) {
+ cap = stackSize;
+ stk.resize(cap * 3 + 3);
+ }
+
+ void push(int stackNum, int value) {
+ if (stk[cap * 3 + stackNum] < cap) {
+ stk[cap * stackNum + stk[cap * 3 + stackNum]] = value;
+ ++stk[cap * 3 + stackNum];
+ }
+ }
+
+ int pop(int stackNum) {
+ if (isEmpty(stackNum)) {
+ return -1;
+ }
+ --stk[cap * 3 + stackNum];
+ return stk[cap * stackNum + stk[cap * 3 + stackNum]];
+ }
+
+ int peek(int stackNum) {
+ return isEmpty(stackNum) ? -1 : stk[cap * stackNum + stk[cap * 3 + stackNum] - 1];
+ }
+
+ bool isEmpty(int stackNum) {
+ return stk[cap * 3 + stackNum] == 0;
+ }
+
+private:
+ int cap;
+ vector stk;
+};
+
+/**
+ * Your TripleInOne object will be instantiated and called as such:
+ * TripleInOne* obj = new TripleInOne(stackSize);
+ * obj->push(stackNum,value);
+ * int param_2 = obj->pop(stackNum);
+ * int param_3 = obj->peek(stackNum);
+ * bool param_4 = obj->isEmpty(stackNum);
+ */
+```
+
+#### Go
+
```go
type TripleInOne struct {
- data []int
- offset [3]int
- stackSize int
+ cap int
+ stk []int
}
func Constructor(stackSize int) TripleInOne {
- total := stackSize * 3
- data := make([]int, total)
- offset := [3]int{}
- for i := 0; i < 3; i++ {
- offset[i] = i * stackSize
- }
- return TripleInOne{
- data: data,
- offset: offset,
- stackSize: stackSize,
- }
+ return TripleInOne{stackSize, make([]int, stackSize*3+3)}
}
func (this *TripleInOne) Push(stackNum int, value int) {
- i := this.offset[stackNum]
- if i < (stackNum+1)*this.stackSize {
- this.data[i] = value
- this.offset[stackNum]++
+ if this.stk[this.cap*3+stackNum] < this.cap {
+ this.stk[this.cap*stackNum+this.stk[this.cap*3+stackNum]] = value
+ this.stk[this.cap*3+stackNum]++
}
}
func (this *TripleInOne) Pop(stackNum int) int {
- i := this.offset[stackNum]
- if i == stackNum*this.stackSize {
+ if this.IsEmpty(stackNum) {
return -1
}
- this.offset[stackNum]--
- return this.data[i-1]
+ this.stk[this.cap*3+stackNum]--
+ return this.stk[this.cap*stackNum+this.stk[this.cap*3+stackNum]]
}
func (this *TripleInOne) Peek(stackNum int) int {
- i := this.offset[stackNum]
- if i == stackNum*this.stackSize {
+ if this.IsEmpty(stackNum) {
return -1
}
- return this.data[i-1]
+ return this.stk[this.cap*stackNum+this.stk[this.cap*3+stackNum]-1]
}
func (this *TripleInOne) IsEmpty(stackNum int) bool {
- return this.offset[stackNum] == stackNum*this.stackSize
+ return this.stk[this.cap*3+stackNum] == 0
}
/**
@@ -182,6 +255,106 @@ func (this *TripleInOne) IsEmpty(stackNum int) bool {
*/
```
+#### TypeScript
+
+```ts
+class TripleInOne {
+ private cap: number;
+ private stk: number[];
+
+ constructor(stackSize: number) {
+ this.cap = stackSize;
+ this.stk = Array(stackSize * 3 + 3).fill(0);
+ }
+
+ push(stackNum: number, value: number): void {
+ if (this.stk[this.cap * 3 + stackNum] < this.cap) {
+ this.stk[this.cap * stackNum + this.stk[this.cap * 3 + stackNum]] = value;
+ this.stk[this.cap * 3 + stackNum]++;
+ }
+ }
+
+ pop(stackNum: number): number {
+ if (this.isEmpty(stackNum)) {
+ return -1;
+ }
+ this.stk[this.cap * 3 + stackNum]--;
+ return this.stk[this.cap * stackNum + this.stk[this.cap * 3 + stackNum]];
+ }
+
+ peek(stackNum: number): number {
+ if (this.isEmpty(stackNum)) {
+ return -1;
+ }
+ return this.stk[this.cap * stackNum + this.stk[this.cap * 3 + stackNum] - 1];
+ }
+
+ isEmpty(stackNum: number): boolean {
+ return this.stk[this.cap * 3 + stackNum] === 0;
+ }
+}
+
+/**
+ * Your TripleInOne object will be instantiated and called as such:
+ * var obj = new TripleInOne(stackSize)
+ * obj.push(stackNum,value)
+ * var param_2 = obj.pop(stackNum)
+ * var param_3 = obj.peek(stackNum)
+ * var param_4 = obj.isEmpty(stackNum)
+ */
+```
+
+#### Swift
+
+```swift
+class TripleInOne {
+ private var cap: Int
+ private var stk: [Int]
+
+ init(_ stackSize: Int) {
+ self.cap = stackSize
+ self.stk = [Int](repeating: 0, count: cap * 3 + 3)
+ }
+
+ func push(_ stackNum: Int, _ value: Int) {
+ if stk[cap * 3 + stackNum] < cap {
+ stk[cap * stackNum + stk[cap * 3 + stackNum]] = value
+ stk[cap * 3 + stackNum] += 1
+ }
+ }
+
+ func pop(_ stackNum: Int) -> Int {
+ if isEmpty(stackNum) {
+ return -1
+ }
+ stk[cap * 3 + stackNum] -= 1
+ return stk[cap * stackNum + stk[cap * 3 + stackNum]]
+ }
+
+ func peek(_ stackNum: Int) -> Int {
+ if isEmpty(stackNum) {
+ return -1
+ }
+ return stk[cap * stackNum + stk[cap * 3 + stackNum] - 1]
+ }
+
+ func isEmpty(_ stackNum: Int) -> Bool {
+ return stk[cap * 3 + stackNum] == 0
+ }
+}
+
+/**
+ * Your TripleInOne object will be instantiated and called as such:
+ * let obj = TripleInOne(stackSize)
+ * obj.push(stackNum,value)
+ * let param_2 = obj.pop(stackNum)
+ * let param_3 = obj.peek(stackNum)
+ * let param_4 = obj.isEmpty(stackNum)
+ */
+```
+
-
+
+
+
diff --git a/lcci/03.01.Three in One/Solution.cpp b/lcci/03.01.Three in One/Solution.cpp
new file mode 100644
index 0000000000000..1da6d47f122ac
--- /dev/null
+++ b/lcci/03.01.Three in One/Solution.cpp
@@ -0,0 +1,43 @@
+class TripleInOne {
+public:
+ TripleInOne(int stackSize) {
+ cap = stackSize;
+ stk.resize(cap * 3 + 3);
+ }
+
+ void push(int stackNum, int value) {
+ if (stk[cap * 3 + stackNum] < cap) {
+ stk[cap * stackNum + stk[cap * 3 + stackNum]] = value;
+ ++stk[cap * 3 + stackNum];
+ }
+ }
+
+ int pop(int stackNum) {
+ if (isEmpty(stackNum)) {
+ return -1;
+ }
+ --stk[cap * 3 + stackNum];
+ return stk[cap * stackNum + stk[cap * 3 + stackNum]];
+ }
+
+ int peek(int stackNum) {
+ return isEmpty(stackNum) ? -1 : stk[cap * stackNum + stk[cap * 3 + stackNum] - 1];
+ }
+
+ bool isEmpty(int stackNum) {
+ return stk[cap * 3 + stackNum] == 0;
+ }
+
+private:
+ int cap;
+ vector stk;
+};
+
+/**
+ * Your TripleInOne object will be instantiated and called as such:
+ * TripleInOne* obj = new TripleInOne(stackSize);
+ * obj->push(stackNum,value);
+ * int param_2 = obj->pop(stackNum);
+ * int param_3 = obj->peek(stackNum);
+ * bool param_4 = obj->isEmpty(stackNum);
+ */
\ No newline at end of file
diff --git a/lcci/03.01.Three in One/Solution.go b/lcci/03.01.Three in One/Solution.go
index 8f2d4bf765e97..8152aea9f3eaf 100644
--- a/lcci/03.01.Three in One/Solution.go
+++ b/lcci/03.01.Three in One/Solution.go
@@ -1,50 +1,36 @@
type TripleInOne struct {
- data []int
- offset [3]int
- stackSize int
+ cap int
+ stk []int
}
func Constructor(stackSize int) TripleInOne {
- total := stackSize * 3
- data := make([]int, total)
- offset := [3]int{}
- for i := 0; i < 3; i++ {
- offset[i] = i * stackSize
- }
- return TripleInOne{
- data: data,
- offset: offset,
- stackSize: stackSize,
- }
+ return TripleInOne{stackSize, make([]int, stackSize*3+3)}
}
func (this *TripleInOne) Push(stackNum int, value int) {
- i := this.offset[stackNum]
- if i < (stackNum+1)*this.stackSize {
- this.data[i] = value
- this.offset[stackNum]++
+ if this.stk[this.cap*3+stackNum] < this.cap {
+ this.stk[this.cap*stackNum+this.stk[this.cap*3+stackNum]] = value
+ this.stk[this.cap*3+stackNum]++
}
}
func (this *TripleInOne) Pop(stackNum int) int {
- i := this.offset[stackNum]
- if i == stackNum*this.stackSize {
+ if this.IsEmpty(stackNum) {
return -1
}
- this.offset[stackNum]--
- return this.data[i-1]
+ this.stk[this.cap*3+stackNum]--
+ return this.stk[this.cap*stackNum+this.stk[this.cap*3+stackNum]]
}
func (this *TripleInOne) Peek(stackNum int) int {
- i := this.offset[stackNum]
- if i == stackNum*this.stackSize {
+ if this.IsEmpty(stackNum) {
return -1
}
- return this.data[i-1]
+ return this.stk[this.cap*stackNum+this.stk[this.cap*3+stackNum]-1]
}
func (this *TripleInOne) IsEmpty(stackNum int) bool {
- return this.offset[stackNum] == stackNum*this.stackSize
+ return this.stk[this.cap*3+stackNum] == 0
}
/**
diff --git a/lcci/03.01.Three in One/Solution.java b/lcci/03.01.Three in One/Solution.java
index 19916ea47f1f3..b1c163cb17683 100644
--- a/lcci/03.01.Three in One/Solution.java
+++ b/lcci/03.01.Three in One/Solution.java
@@ -1,16 +1,16 @@
class TripleInOne {
- private int[] s;
- private int capacity;
+ private int cap;
+ private int[] stk;
public TripleInOne(int stackSize) {
- s = new int[stackSize * 3 + 3];
- capacity = stackSize;
+ cap = stackSize;
+ stk = new int[cap * 3 + 3];
}
public void push(int stackNum, int value) {
- if (s[stackNum + 3 * capacity] < capacity) {
- s[s[stackNum + 3 * capacity] * 3 + stackNum] = value;
- ++s[stackNum + 3 * capacity];
+ if (stk[cap * 3 + stackNum] < cap) {
+ stk[cap * stackNum + stk[cap * 3 + stackNum]] = value;
+ ++stk[cap * 3 + stackNum];
}
}
@@ -18,16 +18,16 @@ public int pop(int stackNum) {
if (isEmpty(stackNum)) {
return -1;
}
- --s[stackNum + 3 * capacity];
- return s[s[stackNum + 3 * capacity] * 3 + stackNum];
+ --stk[cap * 3 + stackNum];
+ return stk[cap * stackNum + stk[cap * 3 + stackNum]];
}
public int peek(int stackNum) {
- return isEmpty(stackNum) ? -1 : s[(s[stackNum + 3 * capacity] - 1) * 3 + stackNum];
+ return isEmpty(stackNum) ? -1 : stk[cap * stackNum + stk[cap * 3 + stackNum] - 1];
}
public boolean isEmpty(int stackNum) {
- return s[stackNum + 3 * capacity] == 0;
+ return stk[cap * 3 + stackNum] == 0;
}
}
diff --git a/lcci/03.01.Three in One/Solution.py b/lcci/03.01.Three in One/Solution.py
index 9a381144f0421..155a822197c0b 100644
--- a/lcci/03.01.Three in One/Solution.py
+++ b/lcci/03.01.Three in One/Solution.py
@@ -1,20 +1,27 @@
class TripleInOne:
+
def __init__(self, stackSize: int):
- self._capacity = stackSize
- self._s = [[], [], []]
+ self.cap = stackSize
+ self.stk = [0] * (self.cap * 3 + 3)
def push(self, stackNum: int, value: int) -> None:
- if len(self._s[stackNum]) < self._capacity:
- self._s[stackNum].append(value)
+ if self.stk[self.cap * 3 + stackNum] < self.cap:
+ self.stk[self.cap * stackNum + self.stk[self.cap * 3 + stackNum]] = value
+ self.stk[self.cap * 3 + stackNum] += 1
def pop(self, stackNum: int) -> int:
- return -1 if self.isEmpty(stackNum) else self._s[stackNum].pop()
+ if self.isEmpty(stackNum):
+ return -1
+ self.stk[self.cap * 3 + stackNum] -= 1
+ return self.stk[self.cap * stackNum + self.stk[self.cap * 3 + stackNum]]
def peek(self, stackNum: int) -> int:
- return -1 if self.isEmpty(stackNum) else self._s[stackNum][-1]
+ if self.isEmpty(stackNum):
+ return -1
+ return self.stk[self.cap * stackNum + self.stk[self.cap * 3 + stackNum] - 1]
def isEmpty(self, stackNum: int) -> bool:
- return len(self._s[stackNum]) == 0
+ return self.stk[self.cap * 3 + stackNum] == 0
# Your TripleInOne object will be instantiated and called as such:
diff --git a/lcci/03.01.Three in One/Solution.swift b/lcci/03.01.Three in One/Solution.swift
new file mode 100644
index 0000000000000..04dd229bb6c98
--- /dev/null
+++ b/lcci/03.01.Three in One/Solution.swift
@@ -0,0 +1,44 @@
+class TripleInOne {
+ private var cap: Int
+ private var stk: [Int]
+
+ init(_ stackSize: Int) {
+ self.cap = stackSize
+ self.stk = [Int](repeating: 0, count: cap * 3 + 3)
+ }
+
+ func push(_ stackNum: Int, _ value: Int) {
+ if stk[cap * 3 + stackNum] < cap {
+ stk[cap * stackNum + stk[cap * 3 + stackNum]] = value
+ stk[cap * 3 + stackNum] += 1
+ }
+ }
+
+ func pop(_ stackNum: Int) -> Int {
+ if isEmpty(stackNum) {
+ return -1
+ }
+ stk[cap * 3 + stackNum] -= 1
+ return stk[cap * stackNum + stk[cap * 3 + stackNum]]
+ }
+
+ func peek(_ stackNum: Int) -> Int {
+ if isEmpty(stackNum) {
+ return -1
+ }
+ return stk[cap * stackNum + stk[cap * 3 + stackNum] - 1]
+ }
+
+ func isEmpty(_ stackNum: Int) -> Bool {
+ return stk[cap * 3 + stackNum] == 0
+ }
+}
+
+/**
+ * Your TripleInOne object will be instantiated and called as such:
+ * let obj = TripleInOne(stackSize)
+ * obj.push(stackNum,value)
+ * let param_2 = obj.pop(stackNum)
+ * let param_3 = obj.peek(stackNum)
+ * let param_4 = obj.isEmpty(stackNum)
+ */
\ No newline at end of file
diff --git a/lcci/03.01.Three in One/Solution.ts b/lcci/03.01.Three in One/Solution.ts
new file mode 100644
index 0000000000000..dafdde9ac8973
--- /dev/null
+++ b/lcci/03.01.Three in One/Solution.ts
@@ -0,0 +1,44 @@
+class TripleInOne {
+ private cap: number;
+ private stk: number[];
+
+ constructor(stackSize: number) {
+ this.cap = stackSize;
+ this.stk = Array(stackSize * 3 + 3).fill(0);
+ }
+
+ push(stackNum: number, value: number): void {
+ if (this.stk[this.cap * 3 + stackNum] < this.cap) {
+ this.stk[this.cap * stackNum + this.stk[this.cap * 3 + stackNum]] = value;
+ this.stk[this.cap * 3 + stackNum]++;
+ }
+ }
+
+ pop(stackNum: number): number {
+ if (this.isEmpty(stackNum)) {
+ return -1;
+ }
+ this.stk[this.cap * 3 + stackNum]--;
+ return this.stk[this.cap * stackNum + this.stk[this.cap * 3 + stackNum]];
+ }
+
+ peek(stackNum: number): number {
+ if (this.isEmpty(stackNum)) {
+ return -1;
+ }
+ return this.stk[this.cap * stackNum + this.stk[this.cap * 3 + stackNum] - 1];
+ }
+
+ isEmpty(stackNum: number): boolean {
+ return this.stk[this.cap * 3 + stackNum] === 0;
+ }
+}
+
+/**
+ * Your TripleInOne object will be instantiated and called as such:
+ * var obj = new TripleInOne(stackSize)
+ * obj.push(stackNum,value)
+ * var param_2 = obj.pop(stackNum)
+ * var param_3 = obj.peek(stackNum)
+ * var param_4 = obj.isEmpty(stackNum)
+ */
diff --git a/lcci/03.02.Min Stack/README.md b/lcci/03.02.Min Stack/README.md
index 5222d092fd2a6..53d742ad9fbfb 100644
--- a/lcci/03.02.Min Stack/README.md
+++ b/lcci/03.02.Min Stack/README.md
@@ -1,14 +1,27 @@
+---
+comments: true
+difficulty: 简单
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/03.02.Min%20Stack/README.md
+---
+
+
+
# [面试题 03.02. 栈的最小值](https://leetcode.cn/problems/min-stack-lcci)
[English Version](/lcci/03.02.Min%20Stack/README_EN.md)
## 题目描述
-
+
+
请设计一个栈,除了常规栈支持的pop与push函数以外,还支持min函数,该函数返回栈元素中的最小值。执行push、pop和min操作的时间复杂度必须为O(1)。
示例:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
+
+
## 解法
+
+
### 方法一:双栈
我们用两个栈来实现,其中`stk1` 用来存储数据,`stk2` 用来存储当前栈中的最小值。初始时,`stk2` 中存储一个极大值。
@@ -22,6 +35,8 @@
+#### Python3
+
```python
class MinStack:
def __init__(self):
@@ -54,6 +69,8 @@ class MinStack:
# param_4 = obj.getMin()
```
+#### Java
+
```java
class MinStack {
private Deque stk1 = new ArrayDeque<>();
@@ -93,6 +110,8 @@ class MinStack {
*/
```
+#### C++
+
```cpp
class MinStack {
public:
@@ -134,6 +153,8 @@ private:
*/
```
+#### Go
+
```go
type MinStack struct {
stk1 []int
@@ -173,6 +194,8 @@ func (this *MinStack) GetMin() int {
*/
```
+#### TypeScript
+
```ts
class MinStack {
stack: number[];
@@ -211,6 +234,8 @@ class MinStack {
*/
```
+#### Rust
+
```rust
use std::collections::VecDeque;
struct MinStack {
@@ -225,7 +250,10 @@ struct MinStack {
impl MinStack {
/** initialize your data structure here. */
fn new() -> Self {
- Self { stack: VecDeque::new(), min_stack: VecDeque::new() }
+ Self {
+ stack: VecDeque::new(),
+ min_stack: VecDeque::new(),
+ }
}
fn push(&mut self, x: i32) {
@@ -249,16 +277,11 @@ impl MinStack {
fn get_min(&self) -> i32 {
*self.min_stack.back().unwrap()
}
-}/**
- * Your MinStack object will be instantiated and called as such:
- * let obj = MinStack::new();
- * obj.push(x);
- * obj.pop();
- * let ret_3: i32 = obj.top();
- * let ret_4: i32 = obj.get_min();
- */
+}
```
+#### C#
+
```cs
public class MinStack {
private Stack stk1 = new Stack();
@@ -298,6 +321,50 @@ public class MinStack {
*/
```
+#### Swift
+
+```swift
+class MinStack {
+ private var stk1: [Int]
+ private var stk2: [Int]
+
+ init() {
+ stk1 = []
+ stk2 = [Int.max]
+ }
+
+ func push(_ x: Int) {
+ stk1.append(x)
+
+ stk2.append(min(x, stk2.last!))
+ }
+
+ func pop() {
+ stk1.removeLast()
+ stk2.removeLast()
+ }
+
+ func top() -> Int {
+ return stk1.last!
+ }
+
+ func getMin() -> Int {
+ return stk2.last!
+ }
+}
+
+/**
+ * Your MinStack object will be instantiated and called as such:
+ * let obj = MinStack();
+ * obj.push(x);
+ * obj.pop();
+ * let param_3 = obj.top();
+ * let param_4 = obj.getMin();
+ */
+```
+
-
+
+
+
diff --git a/lcci/03.02.Min Stack/README_EN.md b/lcci/03.02.Min Stack/README_EN.md
index 053d35e2e8b9e..46bd103a08582 100644
--- a/lcci/03.02.Min Stack/README_EN.md
+++ b/lcci/03.02.Min Stack/README_EN.md
@@ -1,9 +1,19 @@
+---
+comments: true
+difficulty: Easy
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/03.02.Min%20Stack/README_EN.md
+---
+
+
+
# [03.02. Min Stack](https://leetcode.cn/problems/min-stack-lcci)
[中文文档](/lcci/03.02.Min%20Stack/README.md)
## Description
+
+
How would you design a stack which, in addition to push and pop, has a function min which returns the minimum element? Push, pop and min should all operate in 0(1) time.
Example:
@@ -26,8 +36,12 @@ minStack.top(); --> return 0.
minStack.getMin(); --> return -2.
+
+
## Solutions
+
+
### Solution 1: Double Stack
We use two stacks to implement this, where `stk1` is used to store data, and `stk2` is used to store the current minimum value in the stack. Initially, `stk2` stores a very large value.
@@ -41,6 +55,8 @@ For each operation, the time complexity is $O(1)$, and the space complexity is $
+#### Python3
+
```python
class MinStack:
def __init__(self):
@@ -73,6 +89,8 @@ class MinStack:
# param_4 = obj.getMin()
```
+#### Java
+
```java
class MinStack {
private Deque stk1 = new ArrayDeque<>();
@@ -112,6 +130,8 @@ class MinStack {
*/
```
+#### C++
+
```cpp
class MinStack {
public:
@@ -153,6 +173,8 @@ private:
*/
```
+#### Go
+
```go
type MinStack struct {
stk1 []int
@@ -192,6 +214,8 @@ func (this *MinStack) GetMin() int {
*/
```
+#### TypeScript
+
```ts
class MinStack {
stack: number[];
@@ -230,6 +254,8 @@ class MinStack {
*/
```
+#### Rust
+
```rust
use std::collections::VecDeque;
struct MinStack {
@@ -244,7 +270,10 @@ struct MinStack {
impl MinStack {
/** initialize your data structure here. */
fn new() -> Self {
- Self { stack: VecDeque::new(), min_stack: VecDeque::new() }
+ Self {
+ stack: VecDeque::new(),
+ min_stack: VecDeque::new(),
+ }
}
fn push(&mut self, x: i32) {
@@ -268,16 +297,11 @@ impl MinStack {
fn get_min(&self) -> i32 {
*self.min_stack.back().unwrap()
}
-}/**
- * Your MinStack object will be instantiated and called as such:
- * let obj = MinStack::new();
- * obj.push(x);
- * obj.pop();
- * let ret_3: i32 = obj.top();
- * let ret_4: i32 = obj.get_min();
- */
+}
```
+#### C#
+
```cs
public class MinStack {
private Stack stk1 = new Stack();
@@ -317,6 +341,50 @@ public class MinStack {
*/
```
+#### Swift
+
+```swift
+class MinStack {
+ private var stk1: [Int]
+ private var stk2: [Int]
+
+ init() {
+ stk1 = []
+ stk2 = [Int.max]
+ }
+
+ func push(_ x: Int) {
+ stk1.append(x)
+
+ stk2.append(min(x, stk2.last!))
+ }
+
+ func pop() {
+ stk1.removeLast()
+ stk2.removeLast()
+ }
+
+ func top() -> Int {
+ return stk1.last!
+ }
+
+ func getMin() -> Int {
+ return stk2.last!
+ }
+}
+
+/**
+ * Your MinStack object will be instantiated and called as such:
+ * let obj = MinStack();
+ * obj.push(x);
+ * obj.pop();
+ * let param_3 = obj.top();
+ * let param_4 = obj.getMin();
+ */
+```
+
-
+
+
+
diff --git a/lcci/03.02.Min Stack/Solution.rs b/lcci/03.02.Min Stack/Solution.rs
index fcbc64f5abc63..713ca251733ca 100644
--- a/lcci/03.02.Min Stack/Solution.rs
+++ b/lcci/03.02.Min Stack/Solution.rs
@@ -11,7 +11,10 @@ struct MinStack {
impl MinStack {
/** initialize your data structure here. */
fn new() -> Self {
- Self { stack: VecDeque::new(), min_stack: VecDeque::new() }
+ Self {
+ stack: VecDeque::new(),
+ min_stack: VecDeque::new(),
+ }
}
fn push(&mut self, x: i32) {
@@ -35,11 +38,4 @@ impl MinStack {
fn get_min(&self) -> i32 {
*self.min_stack.back().unwrap()
}
-}/**
- * Your MinStack object will be instantiated and called as such:
- * let obj = MinStack::new();
- * obj.push(x);
- * obj.pop();
- * let ret_3: i32 = obj.top();
- * let ret_4: i32 = obj.get_min();
- */
+}
diff --git a/lcci/03.02.Min Stack/Solution.swift b/lcci/03.02.Min Stack/Solution.swift
new file mode 100644
index 0000000000000..f21ae35af479d
--- /dev/null
+++ b/lcci/03.02.Min Stack/Solution.swift
@@ -0,0 +1,37 @@
+class MinStack {
+ private var stk1: [Int]
+ private var stk2: [Int]
+
+ init() {
+ stk1 = []
+ stk2 = [Int.max]
+ }
+
+ func push(_ x: Int) {
+ stk1.append(x)
+
+ stk2.append(min(x, stk2.last!))
+ }
+
+ func pop() {
+ stk1.removeLast()
+ stk2.removeLast()
+ }
+
+ func top() -> Int {
+ return stk1.last!
+ }
+
+ func getMin() -> Int {
+ return stk2.last!
+ }
+}
+
+/**
+ * Your MinStack object will be instantiated and called as such:
+ * let obj = MinStack();
+ * obj.push(x);
+ * obj.pop();
+ * let param_3 = obj.top();
+ * let param_4 = obj.getMin();
+ */
\ No newline at end of file
diff --git a/lcci/03.03.Stack of Plates/README.md b/lcci/03.03.Stack of Plates/README.md
index f51a85641164d..f7885e31c348f 100644
--- a/lcci/03.03.Stack of Plates/README.md
+++ b/lcci/03.03.Stack of Plates/README.md
@@ -1,10 +1,19 @@
+---
+comments: true
+difficulty: 中等
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/03.03.Stack%20of%20Plates/README.md
+---
+
+
+
# [面试题 03.03. 堆盘子](https://leetcode.cn/problems/stack-of-plates-lcci)
[English Version](/lcci/03.03.Stack%20of%20Plates/README_EN.md)
## 题目描述
-
+
+
堆盘子。设想有一堆盘子,堆太高可能会倒下来。因此,在现实生活中,盘子堆到一定高度时,我们就会另外堆一堆盘子。请实现数据结构SetOfStacks
,模拟这种行为。SetOfStacks
应该由多个栈组成,并且在前一个栈填满时新建一个栈。此外,SetOfStacks.push()
和SetOfStacks.pop()
应该与普通栈的操作方法相同(也就是说,pop()返回的值,应该跟只有一个栈时的情况一样)。 进阶:实现一个popAt(int index)
方法,根据指定的子栈,执行pop操作。
当某个栈为空时,应当删除该栈。当栈中没有元素或不存在该栈时,pop
,popAt
应返回 -1.
示例1:
@@ -22,14 +31,26 @@
[null, null, null, null, 2, 1, 3]
+
+
## 解法
+
+
### 方法一:模拟
-用列表模拟栈的集合,每个栈的容量为 `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$ 为元素个数。
+#### Python3
+
```python
class StackOfPlates:
def __init__(self, cap: int):
@@ -62,6 +83,8 @@ class StackOfPlates:
# param_3 = obj.popAt(index)
```
+#### Java
+
```java
class StackOfPlates {
private List> stk = new ArrayList<>();
@@ -106,6 +129,8 @@ class StackOfPlates {
*/
```
+#### C++
+
```cpp
class StackOfPlates {
public:
@@ -114,9 +139,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 +165,8 @@ public:
}
private:
- vector> stk;
int cap;
+ vector> stk;
};
/**
@@ -149,6 +178,8 @@ private:
*/
```
+#### Go
+
```go
type StackOfPlates struct {
stk [][]int
@@ -195,6 +226,8 @@ func (this *StackOfPlates) PopAt(index int) int {
*/
```
+#### TypeScript
+
```ts
class StackOfPlates {
private cap: number;
@@ -248,6 +281,55 @@ class StackOfPlates {
*/
```
+#### Swift
+
+```swift
+class StackOfPlates {
+ private var stacks: [[Int]]
+ private var cap: Int
+
+ init(_ cap: Int) {
+ self.cap = cap
+ self.stacks = []
+ }
+
+ func push(_ val: Int) {
+ if cap == 0 {
+ return
+ }
+ if stacks.isEmpty || stacks.last!.count >= cap {
+ stacks.append([])
+ }
+ stacks[stacks.count - 1].append(val)
+ }
+
+ func pop() -> Int {
+ return popAt(stacks.count - 1)
+ }
+
+ func popAt(_ index: Int) -> Int {
+ guard index >= 0, index < stacks.count, !stacks[index].isEmpty else {
+ return -1
+ }
+ let value = stacks[index].removeLast()
+ if stacks[index].isEmpty {
+ stacks.remove(at: index)
+ }
+ return value
+ }
+}
+
+/**
+ * Your StackOfPlates object will be instantiated and called as such:
+ * let obj = new StackOfPlates(cap);
+ * obj.push(val);
+ * let param_2 = obj.pop();
+ * let param_3 = obj.popAt(index);
+ */
+```
+
-
+
+
+
diff --git a/lcci/03.03.Stack of Plates/README_EN.md b/lcci/03.03.Stack of Plates/README_EN.md
index 55c1ba2995069..b6043a77dbadc 100644
--- a/lcci/03.03.Stack of Plates/README_EN.md
+++ b/lcci/03.03.Stack of Plates/README_EN.md
@@ -1,9 +1,19 @@
+---
+comments: true
+difficulty: Medium
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/03.03.Stack%20of%20Plates/README_EN.md
+---
+
+
+
# [03.03. Stack of Plates](https://leetcode.cn/problems/stack-of-plates-lcci)
[中文文档](/lcci/03.03.Stack%20of%20Plates/README.md)
## Description
+
+
Imagine a (literal) stack of plates. If the stack gets too high, it might topple. Therefore, in real life, we would likely start a new stack when the previous stack exceeds some threshold. Implement a data structure SetOfStacks
that mimics this. SetOfStacks
should be composed of several stacks and should create a new stack once the previous one exceeds capacity. SetOfStacks.push()
and SetOfStacks.pop()
should behave identically to a single stack (that is, pop()
should return the same values as it would if there were just a single stack). Follow Up: Implement a function popAt(int index)
which performs a pop operation on a specific sub-stack.
You should delete the sub-stack when it becomes empty. pop
, popAt
should return -1 when there's no element to pop.
Example1:
@@ -37,12 +47,26 @@
+
+
## 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.
+#### Python3
+
```python
class StackOfPlates:
def __init__(self, cap: int):
@@ -75,6 +99,8 @@ class StackOfPlates:
# param_3 = obj.popAt(index)
```
+#### Java
+
```java
class StackOfPlates {
private List> stk = new ArrayList<>();
@@ -119,6 +145,8 @@ class StackOfPlates {
*/
```
+#### C++
+
```cpp
class StackOfPlates {
public:
@@ -127,9 +155,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 +181,8 @@ public:
}
private:
- vector> stk;
int cap;
+ vector> stk;
};
/**
@@ -162,6 +194,8 @@ private:
*/
```
+#### Go
+
```go
type StackOfPlates struct {
stk [][]int
@@ -208,6 +242,8 @@ func (this *StackOfPlates) PopAt(index int) int {
*/
```
+#### TypeScript
+
```ts
class StackOfPlates {
private cap: number;
@@ -261,6 +297,55 @@ class StackOfPlates {
*/
```
+#### Swift
+
+```swift
+class StackOfPlates {
+ private var stacks: [[Int]]
+ private var cap: Int
+
+ init(_ cap: Int) {
+ self.cap = cap
+ self.stacks = []
+ }
+
+ func push(_ val: Int) {
+ if cap == 0 {
+ return
+ }
+ if stacks.isEmpty || stacks.last!.count >= cap {
+ stacks.append([])
+ }
+ stacks[stacks.count - 1].append(val)
+ }
+
+ func pop() -> Int {
+ return popAt(stacks.count - 1)
+ }
+
+ func popAt(_ index: Int) -> Int {
+ guard index >= 0, index < stacks.count, !stacks[index].isEmpty else {
+ return -1
+ }
+ let value = stacks[index].removeLast()
+ if stacks[index].isEmpty {
+ stacks.remove(at: index)
+ }
+ return value
+ }
+}
+
+/**
+ * Your StackOfPlates object will be instantiated and called as such:
+ * let obj = new StackOfPlates(cap);
+ * obj.push(val);
+ * let param_2 = obj.pop();
+ * let param_3 = obj.popAt(index);
+ */
+```
+
-
+
+
+
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.03.Stack of Plates/Solution.swift b/lcci/03.03.Stack of Plates/Solution.swift
new file mode 100644
index 0000000000000..6b1c7f4aa7065
--- /dev/null
+++ b/lcci/03.03.Stack of Plates/Solution.swift
@@ -0,0 +1,42 @@
+class StackOfPlates {
+ private var stacks: [[Int]]
+ private var cap: Int
+
+ init(_ cap: Int) {
+ self.cap = cap
+ self.stacks = []
+ }
+
+ func push(_ val: Int) {
+ if cap == 0 {
+ return
+ }
+ if stacks.isEmpty || stacks.last!.count >= cap {
+ stacks.append([])
+ }
+ stacks[stacks.count - 1].append(val)
+ }
+
+ func pop() -> Int {
+ return popAt(stacks.count - 1)
+ }
+
+ func popAt(_ index: Int) -> Int {
+ guard index >= 0, index < stacks.count, !stacks[index].isEmpty else {
+ return -1
+ }
+ let value = stacks[index].removeLast()
+ if stacks[index].isEmpty {
+ stacks.remove(at: index)
+ }
+ return value
+ }
+}
+
+/**
+ * Your StackOfPlates object will be instantiated and called as such:
+ * let obj = new StackOfPlates(cap);
+ * obj.push(val);
+ * let param_2 = obj.pop();
+ * let param_3 = obj.popAt(index);
+ */
\ No newline at end of file
diff --git a/lcci/03.04.Implement Queue using Stacks/README.md b/lcci/03.04.Implement Queue using Stacks/README.md
index 18f76c3c9be14..aa8fa989f56b8 100644
--- a/lcci/03.04.Implement Queue using Stacks/README.md
+++ b/lcci/03.04.Implement Queue using Stacks/README.md
@@ -1,55 +1,67 @@
+---
+comments: true
+difficulty: 简单
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/03.04.Implement%20Queue%20using%20Stacks/README.md
+---
+
+
+
# [面试题 03.04. 化栈为队](https://leetcode.cn/problems/implement-queue-using-stacks-lcci)
[English Version](/lcci/03.04.Implement%20Queue%20using%20Stacks/README_EN.md)
## 题目描述
-
+
+
实现一个MyQueue类,该类用两个栈来实现一个队列。
示例:
MyQueue queue = new MyQueue();
queue.push(1);
queue.push(2);
queue.peek(); // 返回 1
queue.pop(); // 返回 1
queue.empty(); // 返回 false
说明:
- 你只能使用标准的栈操作 -- 也就是只有
push to top
, peek/pop from top
, size
和 is empty
操作是合法的。 - 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
- 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)。
+
+
## 解法
-### 方法一
+
+
+### 方法一:双栈
+
+我们使用两个栈,其中栈 `stk1`用于入队,另一个栈 `stk2` 用于出队。
+
+入队时,直接将元素入栈 `stk1`。时间复杂度 $O(1)$。
+
+出队时,先判断栈 `stk2` 是否为空,如果为空,则将栈 `stk1` 中的元素全部出栈并入栈 `stk2`,然后再从栈 `stk2` 中出栈一个元素。如果栈 `stk2` 不为空,则直接从栈 `stk2` 中出栈一个元素。均摊时间复杂度 $O(1)$。
+
+获取队首元素时,先判断栈 `stk2` 是否为空,如果为空,则将栈 `stk1` 中的元素全部出栈并入栈 `stk2`,然后再从栈 `stk2` 中获取栈顶元素。如果栈 `stk2` 不为空,则直接从栈 `stk2` 中获取栈顶元素。均摊时间复杂度 $O(1)$。
+
+判断队列是否为空时,只要判断两个栈是否都为空即可。时间复杂度 $O(1)$。
+#### Python3
+
```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:
@@ -60,45 +72,40 @@ class MyQueue:
# param_4 = obj.empty()
```
+#### Java
+
```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 +119,96 @@ class MyQueue {
*/
```
+#### C++
+
+```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
+
```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]
+ }
}
}
@@ -170,41 +222,41 @@ func (this *MyQueue) transfer() {
*/
```
+#### TypeScript
+
```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 +271,102 @@ class MyQueue {
*/
```
+#### Rust
+
+```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);
+ }
+ }
+ }
+}
+```
+
+#### Swift
+
+```swift
+class MyQueue {
+ private var stk1: [Int] = []
+ private var stk2: [Int] = []
+
+ init() {}
+
+ func push(_ x: Int) {
+ stk1.append(x)
+ }
+
+ @discardableResult
+ func pop() -> Int {
+ move()
+ return stk2.removeLast()
+ }
+
+ func peek() -> Int {
+ move()
+ return stk2.last!
+ }
+
+ func empty() -> Bool {
+ return stk1.isEmpty && stk2.isEmpty
+ }
+
+ private func move() {
+ if stk2.isEmpty {
+ while !stk1.isEmpty {
+ stk2.append(stk1.removeLast())
+ }
+ }
+ }
+}
+
+/**
+ * Your MyQueue object will be instantiated and called as such:
+ * let obj = new MyQueue();
+ * obj.push(x);
+ * let param_2 = obj.pop();
+ * let param_3 = obj.peek();
+ * var myValue : Bool
+ * myValue = 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..71080d2024622 100644
--- a/lcci/03.04.Implement Queue using Stacks/README_EN.md
+++ b/lcci/03.04.Implement Queue using Stacks/README_EN.md
@@ -1,9 +1,19 @@
+---
+comments: true
+difficulty: Easy
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/03.04.Implement%20Queue%20using%20Stacks/README_EN.md
+---
+
+
+
# [03.04. Implement Queue using Stacks](https://leetcode.cn/problems/implement-queue-using-stacks-lcci)
[中文文档](/lcci/03.04.Implement%20Queue%20using%20Stacks/README.md)
## Description
+
+
Implement a MyQueue class which implements a queue using two stacks.
@@ -38,49 +48,52 @@ 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)$.
+#### Python3
+
```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:
@@ -91,45 +104,40 @@ class MyQueue:
# param_4 = obj.empty()
```
+#### Java
+
```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 +151,96 @@ class MyQueue {
*/
```
+#### C++
+
+```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
+
```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]
+ }
}
}
@@ -201,41 +254,41 @@ func (this *MyQueue) transfer() {
*/
```
+#### TypeScript
+
```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 +303,102 @@ class MyQueue {
*/
```
+#### Rust
+
+```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);
+ }
+ }
+ }
+}
+```
+
+#### Swift
+
+```swift
+class MyQueue {
+ private var stk1: [Int] = []
+ private var stk2: [Int] = []
+
+ init() {}
+
+ func push(_ x: Int) {
+ stk1.append(x)
+ }
+
+ @discardableResult
+ func pop() -> Int {
+ move()
+ return stk2.removeLast()
+ }
+
+ func peek() -> Int {
+ move()
+ return stk2.last!
+ }
+
+ func empty() -> Bool {
+ return stk1.isEmpty && stk2.isEmpty
+ }
+
+ private func move() {
+ if stk2.isEmpty {
+ while !stk1.isEmpty {
+ stk2.append(stk1.removeLast())
+ }
+ }
+ }
+}
+
+/**
+ * Your MyQueue object will be instantiated and called as such:
+ * let obj = new MyQueue();
+ * obj.push(x);
+ * let param_2 = obj.pop();
+ * let param_3 = obj.peek();
+ * var myValue : Bool
+ * myValue = 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..a08427c055f69
--- /dev/null
+++ b/lcci/03.04.Implement Queue using Stacks/Solution.rs
@@ -0,0 +1,41 @@
+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);
+ }
+ }
+ }
+}
diff --git a/lcci/03.04.Implement Queue using Stacks/Solution.swift b/lcci/03.04.Implement Queue using Stacks/Solution.swift
new file mode 100644
index 0000000000000..e2aafc5b74060
--- /dev/null
+++ b/lcci/03.04.Implement Queue using Stacks/Solution.swift
@@ -0,0 +1,43 @@
+class MyQueue {
+ private var stk1: [Int] = []
+ private var stk2: [Int] = []
+
+ init() {}
+
+ func push(_ x: Int) {
+ stk1.append(x)
+ }
+
+ @discardableResult
+ func pop() -> Int {
+ move()
+ return stk2.removeLast()
+ }
+
+ func peek() -> Int {
+ move()
+ return stk2.last!
+ }
+
+ func empty() -> Bool {
+ return stk1.isEmpty && stk2.isEmpty
+ }
+
+ private func move() {
+ if stk2.isEmpty {
+ while !stk1.isEmpty {
+ stk2.append(stk1.removeLast())
+ }
+ }
+ }
+}
+
+/**
+ * Your MyQueue object will be instantiated and called as such:
+ * let obj = new MyQueue();
+ * obj.push(x);
+ * let param_2 = obj.pop();
+ * let param_3 = obj.peek();
+ * var myValue : Bool
+ * myValue = obj.empty();
+ */
\ No newline at end of file
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/lcci/03.05.Sort of Stacks/README.md b/lcci/03.05.Sort of Stacks/README.md
index 7237b9d2c44ad..3e8213cb73064 100644
--- a/lcci/03.05.Sort of Stacks/README.md
+++ b/lcci/03.05.Sort of Stacks/README.md
@@ -1,10 +1,19 @@
+---
+comments: true
+difficulty: 中等
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/03.05.Sort%20of%20Stacks/README.md
+---
+
+
+
# [面试题 03.05. 栈排序](https://leetcode.cn/problems/sort-of-stacks-lcci)
[English Version](/lcci/03.05.Sort%20of%20Stacks/README_EN.md)
## 题目描述
-
+
+
栈排序。 编写程序,对栈进行排序使最小元素位于栈顶。最多只能使用一个其他的临时栈存放数据,但不得将元素复制到别的数据结构(如数组)中。该栈支持如下操作:push
、pop
、peek
和 isEmpty
。当栈为空时,peek
返回 -1。
示例1:
@@ -31,66 +40,95 @@
栈中的元素数目在[0, 5000]范围内。
+
+
## 解法
-### 方法一
+
+
+### 方法一:栈 + 辅助栈
+
+我们定义一个栈 $stk$,用于存放元素。
+
+在 `push` 操作中,我们定义一个辅助栈 $t$,用于存放 $stk$ 中比当前元素小的元素。我们将 $stk$ 中比当前元素小的元素全部弹出并存放到 $t$ 中,然后将当前元素压入 $stk$,最后将 $t$ 中的元素全部弹出并压入 $stk$。时间复杂度 $O(n)$。
+
+在 `pop` 操作中,我们只需要判断 $stk$ 是否为空,如果不为空,则弹出栈顶元素。时间复杂度 $O(1)$。
+
+在 `peek` 操作中,我们只需要判断 $stk$ 是否为空,如果为空则返回 -1,否则返回栈顶元素。时间复杂度 $O(1)$。
+
+在 `isEmpty` 操作中,我们只需要判断 $stk$ 是否为空。时间复杂度 $O(1)$。
+
+空间复杂度 $O(n)$,其中 $n$ 为栈中元素的个数。
+#### Python3
+
```python
class SortedStack:
+
def __init__(self):
- self.s = []
+ self.stk = []
def push(self, val: int) -> None:
t = []
- while not self.isEmpty() and self.s[-1] < val:
- t.append(self.s.pop())
- self.s.append(val)
- while len(t) > 0:
- self.s.append(t.pop())
+ while self.stk and self.stk[-1] < val:
+ t.append(self.stk.pop())
+ self.stk.append(val)
+ while t:
+ self.stk.append(t.pop())
def pop(self) -> None:
if not self.isEmpty():
- self.s.pop()
+ self.stk.pop()
def peek(self) -> int:
- return -1 if self.isEmpty() else self.s[-1]
+ return -1 if self.isEmpty() else self.stk[-1]
def isEmpty(self) -> bool:
- return len(self.s) == 0
+ return not self.stk
+
+
+# Your SortedStack object will be instantiated and called as such:
+# obj = SortedStack()
+# obj.push(val)
+# obj.pop()
+# param_3 = obj.peek()
+# param_4 = obj.isEmpty()
```
+#### Java
+
```java
class SortedStack {
- private Stack s;
+ private Deque stk = new ArrayDeque<>();
+
public SortedStack() {
- s = new Stack<>();
}
public void push(int val) {
- Stack t = new Stack<>();
- while (!isEmpty() && s.peek() < val) {
- t.push(s.pop());
+ Deque t = new ArrayDeque<>();
+ while (!stk.isEmpty() && stk.peek() < val) {
+ t.push(stk.pop());
}
- s.push(val);
+ stk.push(val);
while (!t.isEmpty()) {
- s.push(t.pop());
+ stk.push(t.pop());
}
}
public void pop() {
if (!isEmpty()) {
- s.pop();
+ stk.pop();
}
}
public int peek() {
- return isEmpty() ? -1 : s.peek();
+ return isEmpty() ? -1 : stk.peek();
}
public boolean isEmpty() {
- return s.isEmpty();
+ return stk.isEmpty();
}
}
@@ -104,74 +142,135 @@ class SortedStack {
*/
```
+#### C++
+
+```cpp
+class SortedStack {
+public:
+ SortedStack() {
+ }
+
+ void push(int val) {
+ stack t;
+ while (!stk.empty() && stk.top() < val) {
+ t.push(stk.top());
+ stk.pop();
+ }
+ stk.push(val);
+ while (!t.empty()) {
+ stk.push(t.top());
+ t.pop();
+ }
+ }
+
+ void pop() {
+ if (!isEmpty()) {
+ stk.pop();
+ }
+ }
+
+ int peek() {
+ return isEmpty() ? -1 : stk.top();
+ }
+
+ bool isEmpty() {
+ return stk.empty();
+ }
+
+private:
+ stack stk;
+};
+
+/**
+ * Your SortedStack object will be instantiated and called as such:
+ * SortedStack* obj = new SortedStack();
+ * obj->push(val);
+ * obj->pop();
+ * int param_3 = obj->peek();
+ * bool param_4 = obj->isEmpty();
+ */
+```
+
+#### Go
+
```go
type SortedStack struct {
- data []int
+ stk []int
}
func Constructor() SortedStack {
- return SortedStack{make([]int, 0)}
+ return SortedStack{}
}
-func (s *SortedStack) Push(val int) {
- temp := make([]int, 0)
- for !s.IsEmpty() && s.Peek() < val {
- temp = append(temp, s.Peek())
- s.Pop()
+func (this *SortedStack) Push(val int) {
+ t := make([]int, 0)
+ for len(this.stk) > 0 && this.stk[len(this.stk)-1] < val {
+ t = append(t, this.stk[len(this.stk)-1])
+ this.stk = this.stk[:len(this.stk)-1]
}
- s.data = append(s.data, val)
- for len(temp) > 0 {
- s.data = append(s.data, temp[len(temp)-1])
- temp = temp[:len(temp)-1]
+ this.stk = append(this.stk, val)
+ for i := len(t) - 1; i >= 0; i-- {
+ this.stk = append(this.stk, t[i])
}
}
-func (s *SortedStack) Pop() {
- if !s.IsEmpty() {
- s.data = s.data[:len(s.data)-1]
+func (this *SortedStack) Pop() {
+ if !this.IsEmpty() {
+ this.stk = this.stk[:len(this.stk)-1]
}
}
-func (s *SortedStack) Peek() int {
- if !s.IsEmpty() {
- return s.data[len(s.data)-1]
+func (this *SortedStack) Peek() int {
+ if this.IsEmpty() {
+ return -1
}
- return -1
+ return this.stk[len(this.stk)-1]
}
-func (s *SortedStack) IsEmpty() bool {
- return len(s.data) == 0
+func (this *SortedStack) IsEmpty() bool {
+ return len(this.stk) == 0
}
+
+/**
+ * Your SortedStack object will be instantiated and called as such:
+ * obj := Constructor();
+ * obj.Push(val);
+ * obj.Pop();
+ * param_3 := obj.Peek();
+ * param_4 := obj.IsEmpty();
+ */
```
+#### TypeScript
+
```ts
class SortedStack {
- stack: number[];
- constructor() {
- this.stack = [];
- }
+ private stk: number[] = [];
+ constructor() {}
push(val: number): void {
- let t = [];
- while (!this.isEmpty() && this.peek() < val) {
- t.push(this.stack.pop());
+ const t: number[] = [];
+ while (this.stk.length > 0 && this.stk.at(-1)! < val) {
+ t.push(this.stk.pop()!);
}
- this.stack.push(val);
+ this.stk.push(val);
while (t.length > 0) {
- this.stack.push(t.pop());
+ this.stk.push(t.pop()!);
}
}
pop(): void {
- this.stack.pop();
+ if (!this.isEmpty()) {
+ this.stk.pop();
+ }
}
peek(): number {
- return this.isEmpty() ? -1 : this.stack[this.stack.length - 1];
+ return this.isEmpty() ? -1 : this.stk.at(-1)!;
}
isEmpty(): boolean {
- return this.stack.length == 0;
+ return this.stk.length === 0;
}
}
@@ -185,100 +284,105 @@ class SortedStack {
*/
```
+#### Rust
+
```rust
use std::collections::VecDeque;
+
struct SortedStack {
- stack: VecDeque,
+ stk: VecDeque,
}
-/**
- * `&self` means the method takes an immutable reference.
- * If you need a mutable reference, change it to `&mut self` instead.
- */
impl SortedStack {
fn new() -> Self {
- Self { stack: VecDeque::new() }
+ SortedStack {
+ stk: VecDeque::new(),
+ }
}
fn push(&mut self, val: i32) {
- if self.is_empty() || self.peek() > val {
- self.stack.push_back(val);
- return;
+ let mut t = VecDeque::new();
+ while let Some(top) = self.stk.pop_back() {
+ if top < val {
+ t.push_back(top);
+ } else {
+ self.stk.push_back(top);
+ break;
+ }
+ }
+ self.stk.push_back(val);
+ while let Some(top) = t.pop_back() {
+ self.stk.push_back(top);
}
- let t = self.stack.pop_back().unwrap();
- self.push(val);
- self.stack.push_back(t);
}
fn pop(&mut self) {
- self.stack.pop_back();
+ if !self.is_empty() {
+ self.stk.pop_back();
+ }
}
fn peek(&self) -> i32 {
- *self.stack.back().unwrap_or(&-1)
+ if self.is_empty() {
+ -1
+ } else {
+ *self.stk.back().unwrap()
+ }
}
fn is_empty(&self) -> bool {
- self.stack.is_empty()
+ self.stk.is_empty()
}
-}/**
- * Your SortedStack object will be instantiated and called as such:
- * let obj = SortedStack::new();
- * obj.push(val);
- * obj.pop();
- * let ret_3: i32 = obj.peek();
- * let ret_4: bool = obj.is_empty();
- */
+}
```
-
-
-### 方法二
-
-
+#### Swift
-```ts
+```swift
class SortedStack {
- private stack: number[];
+ private var stk: [Int] = []
- constructor() {
- this.stack = [];
- }
+ init() {}
- push(val: number): void {
- if (this.isEmpty() || this.peek() > val) {
- this.stack.push(val);
- return;
+ func push(_ val: Int) {
+ var temp: [Int] = []
+ while let top = stk.last, top < val {
+ temp.append(stk.removeLast())
+ }
+ stk.append(val)
+ while let last = temp.popLast() {
+ stk.append(last)
}
-
- const tmp = this.stack.pop();
- this.push(val);
- this.stack.push(tmp);
}
- pop(): void {
- this.stack.pop();
+ func pop() {
+ if !isEmpty() {
+ stk.removeLast()
+ }
}
- peek(): number {
- return this.stack[this.stack.length - 1] ?? -1;
+ func peek() -> Int {
+ return isEmpty() ? -1 : stk.last!
}
- isEmpty(): boolean {
- return this.stack.length === 0;
+ func isEmpty() -> Bool {
+ return stk.isEmpty
}
}
/**
* Your SortedStack object will be instantiated and called as such:
- * var obj = new SortedStack()
- * obj.push(val)
- * obj.pop()
- * var param_3 = obj.peek()
- * var param_4 = obj.isEmpty()
+ * let obj = new SortedStack();
+ * obj.push(val);
+ * obj.pop();
+ * let param_3 = obj.peek();
+ * var myVar: Bool;
+ * myVar = obj.isEmpty();
*/
```
-
+
+
+
diff --git a/lcci/03.05.Sort of Stacks/README_EN.md b/lcci/03.05.Sort of Stacks/README_EN.md
index 067fe202e020d..378a4fec37be9 100644
--- a/lcci/03.05.Sort of Stacks/README_EN.md
+++ b/lcci/03.05.Sort of Stacks/README_EN.md
@@ -1,9 +1,19 @@
+---
+comments: true
+difficulty: Medium
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/03.05.Sort%20of%20Stacks/README_EN.md
+---
+
+
+
# [03.05. Sort of Stacks](https://leetcode.cn/problems/sort-of-stacks-lcci)
[中文文档](/lcci/03.05.Sort%20of%20Stacks/README.md)
## Description
+
+
Write a program to sort a stack such that the smallest items are on the top. You can use an additional temporary stack, but you may not copy the elements into any other data structure (such as an array). The stack supports the following operations: push
, pop
, peek
, and isEmpty
. When the stack is empty, peek
should return -1.
Example1:
@@ -44,66 +54,95 @@
The total number of elements in the stack is within the range [0, 5000].
+
+
## Solutions
-### Solution 1
+
+
+### Solution 1: Stack + Auxiliary Stack
+
+We define a stack $stk$ for storing elements.
+
+In the `push` operation, we define an auxiliary stack $t$ for storing elements in $stk$ that are smaller than the current element. We pop all elements smaller than the current element from $stk$ and store them in $t$, then push the current element into $stk$, and finally pop all elements from $t$ and push them back into $stk$. The time complexity is $O(n)$.
+
+In the `pop` operation, we just need to check if $stk$ is empty. If it's not, we pop the top element. The time complexity is $O(1)$.
+
+In the `peek` operation, we just need to check if $stk$ is empty. If it is, we return -1, otherwise, we return the top element. The time complexity is $O(1)$.
+
+In the `isEmpty` operation, we just need to check if $stk$ is empty. The time complexity is $O(1)$.
+
+The space complexity is $O(n)$, where $n$ is the number of elements in the stack.
+#### Python3
+
```python
class SortedStack:
+
def __init__(self):
- self.s = []
+ self.stk = []
def push(self, val: int) -> None:
t = []
- while not self.isEmpty() and self.s[-1] < val:
- t.append(self.s.pop())
- self.s.append(val)
- while len(t) > 0:
- self.s.append(t.pop())
+ while self.stk and self.stk[-1] < val:
+ t.append(self.stk.pop())
+ self.stk.append(val)
+ while t:
+ self.stk.append(t.pop())
def pop(self) -> None:
if not self.isEmpty():
- self.s.pop()
+ self.stk.pop()
def peek(self) -> int:
- return -1 if self.isEmpty() else self.s[-1]
+ return -1 if self.isEmpty() else self.stk[-1]
def isEmpty(self) -> bool:
- return len(self.s) == 0
+ return not self.stk
+
+
+# Your SortedStack object will be instantiated and called as such:
+# obj = SortedStack()
+# obj.push(val)
+# obj.pop()
+# param_3 = obj.peek()
+# param_4 = obj.isEmpty()
```
+#### Java
+
```java
class SortedStack {
- private Stack s;
+ private Deque stk = new ArrayDeque<>();
+
public SortedStack() {
- s = new Stack<>();
}
public void push(int val) {
- Stack t = new Stack<>();
- while (!isEmpty() && s.peek() < val) {
- t.push(s.pop());
+ Deque t = new ArrayDeque<>();
+ while (!stk.isEmpty() && stk.peek() < val) {
+ t.push(stk.pop());
}
- s.push(val);
+ stk.push(val);
while (!t.isEmpty()) {
- s.push(t.pop());
+ stk.push(t.pop());
}
}
public void pop() {
if (!isEmpty()) {
- s.pop();
+ stk.pop();
}
}
public int peek() {
- return isEmpty() ? -1 : s.peek();
+ return isEmpty() ? -1 : stk.peek();
}
public boolean isEmpty() {
- return s.isEmpty();
+ return stk.isEmpty();
}
}
@@ -117,74 +156,135 @@ class SortedStack {
*/
```
+#### C++
+
+```cpp
+class SortedStack {
+public:
+ SortedStack() {
+ }
+
+ void push(int val) {
+ stack t;
+ while (!stk.empty() && stk.top() < val) {
+ t.push(stk.top());
+ stk.pop();
+ }
+ stk.push(val);
+ while (!t.empty()) {
+ stk.push(t.top());
+ t.pop();
+ }
+ }
+
+ void pop() {
+ if (!isEmpty()) {
+ stk.pop();
+ }
+ }
+
+ int peek() {
+ return isEmpty() ? -1 : stk.top();
+ }
+
+ bool isEmpty() {
+ return stk.empty();
+ }
+
+private:
+ stack stk;
+};
+
+/**
+ * Your SortedStack object will be instantiated and called as such:
+ * SortedStack* obj = new SortedStack();
+ * obj->push(val);
+ * obj->pop();
+ * int param_3 = obj->peek();
+ * bool param_4 = obj->isEmpty();
+ */
+```
+
+#### Go
+
```go
type SortedStack struct {
- data []int
+ stk []int
}
func Constructor() SortedStack {
- return SortedStack{make([]int, 0)}
+ return SortedStack{}
}
-func (s *SortedStack) Push(val int) {
- temp := make([]int, 0)
- for !s.IsEmpty() && s.Peek() < val {
- temp = append(temp, s.Peek())
- s.Pop()
+func (this *SortedStack) Push(val int) {
+ t := make([]int, 0)
+ for len(this.stk) > 0 && this.stk[len(this.stk)-1] < val {
+ t = append(t, this.stk[len(this.stk)-1])
+ this.stk = this.stk[:len(this.stk)-1]
}
- s.data = append(s.data, val)
- for len(temp) > 0 {
- s.data = append(s.data, temp[len(temp)-1])
- temp = temp[:len(temp)-1]
+ this.stk = append(this.stk, val)
+ for i := len(t) - 1; i >= 0; i-- {
+ this.stk = append(this.stk, t[i])
}
}
-func (s *SortedStack) Pop() {
- if !s.IsEmpty() {
- s.data = s.data[:len(s.data)-1]
+func (this *SortedStack) Pop() {
+ if !this.IsEmpty() {
+ this.stk = this.stk[:len(this.stk)-1]
}
}
-func (s *SortedStack) Peek() int {
- if !s.IsEmpty() {
- return s.data[len(s.data)-1]
+func (this *SortedStack) Peek() int {
+ if this.IsEmpty() {
+ return -1
}
- return -1
+ return this.stk[len(this.stk)-1]
}
-func (s *SortedStack) IsEmpty() bool {
- return len(s.data) == 0
+func (this *SortedStack) IsEmpty() bool {
+ return len(this.stk) == 0
}
+
+/**
+ * Your SortedStack object will be instantiated and called as such:
+ * obj := Constructor();
+ * obj.Push(val);
+ * obj.Pop();
+ * param_3 := obj.Peek();
+ * param_4 := obj.IsEmpty();
+ */
```
+#### TypeScript
+
```ts
class SortedStack {
- stack: number[];
- constructor() {
- this.stack = [];
- }
+ private stk: number[] = [];
+ constructor() {}
push(val: number): void {
- let t = [];
- while (!this.isEmpty() && this.peek() < val) {
- t.push(this.stack.pop());
+ const t: number[] = [];
+ while (this.stk.length > 0 && this.stk.at(-1)! < val) {
+ t.push(this.stk.pop()!);
}
- this.stack.push(val);
+ this.stk.push(val);
while (t.length > 0) {
- this.stack.push(t.pop());
+ this.stk.push(t.pop()!);
}
}
pop(): void {
- this.stack.pop();
+ if (!this.isEmpty()) {
+ this.stk.pop();
+ }
}
peek(): number {
- return this.isEmpty() ? -1 : this.stack[this.stack.length - 1];
+ return this.isEmpty() ? -1 : this.stk.at(-1)!;
}
isEmpty(): boolean {
- return this.stack.length == 0;
+ return this.stk.length === 0;
}
}
@@ -198,100 +298,105 @@ class SortedStack {
*/
```
+#### Rust
+
```rust
use std::collections::VecDeque;
+
struct SortedStack {
- stack: VecDeque,
+ stk: VecDeque,
}
-/**
- * `&self` means the method takes an immutable reference.
- * If you need a mutable reference, change it to `&mut self` instead.
- */
impl SortedStack {
fn new() -> Self {
- Self { stack: VecDeque::new() }
+ SortedStack {
+ stk: VecDeque::new(),
+ }
}
fn push(&mut self, val: i32) {
- if self.is_empty() || self.peek() > val {
- self.stack.push_back(val);
- return;
+ let mut t = VecDeque::new();
+ while let Some(top) = self.stk.pop_back() {
+ if top < val {
+ t.push_back(top);
+ } else {
+ self.stk.push_back(top);
+ break;
+ }
+ }
+ self.stk.push_back(val);
+ while let Some(top) = t.pop_back() {
+ self.stk.push_back(top);
}
- let t = self.stack.pop_back().unwrap();
- self.push(val);
- self.stack.push_back(t);
}
fn pop(&mut self) {
- self.stack.pop_back();
+ if !self.is_empty() {
+ self.stk.pop_back();
+ }
}
fn peek(&self) -> i32 {
- *self.stack.back().unwrap_or(&-1)
+ if self.is_empty() {
+ -1
+ } else {
+ *self.stk.back().unwrap()
+ }
}
fn is_empty(&self) -> bool {
- self.stack.is_empty()
+ self.stk.is_empty()
}
-}/**
- * Your SortedStack object will be instantiated and called as such:
- * let obj = SortedStack::new();
- * obj.push(val);
- * obj.pop();
- * let ret_3: i32 = obj.peek();
- * let ret_4: bool = obj.is_empty();
- */
+}
```
-
-
-### Solution 2
-
-
+#### Swift
-```ts
+```swift
class SortedStack {
- private stack: number[];
+ private var stk: [Int] = []
- constructor() {
- this.stack = [];
- }
+ init() {}
- push(val: number): void {
- if (this.isEmpty() || this.peek() > val) {
- this.stack.push(val);
- return;
+ func push(_ val: Int) {
+ var temp: [Int] = []
+ while let top = stk.last, top < val {
+ temp.append(stk.removeLast())
+ }
+ stk.append(val)
+ while let last = temp.popLast() {
+ stk.append(last)
}
-
- const tmp = this.stack.pop();
- this.push(val);
- this.stack.push(tmp);
}
- pop(): void {
- this.stack.pop();
+ func pop() {
+ if !isEmpty() {
+ stk.removeLast()
+ }
}
- peek(): number {
- return this.stack[this.stack.length - 1] ?? -1;
+ func peek() -> Int {
+ return isEmpty() ? -1 : stk.last!
}
- isEmpty(): boolean {
- return this.stack.length === 0;
+ func isEmpty() -> Bool {
+ return stk.isEmpty
}
}
/**
* Your SortedStack object will be instantiated and called as such:
- * var obj = new SortedStack()
- * obj.push(val)
- * obj.pop()
- * var param_3 = obj.peek()
- * var param_4 = obj.isEmpty()
+ * let obj = new SortedStack();
+ * obj.push(val);
+ * obj.pop();
+ * let param_3 = obj.peek();
+ * var myVar: Bool;
+ * myVar = obj.isEmpty();
*/
```
-
+
+
+
diff --git a/lcci/03.05.Sort of Stacks/Solution.cpp b/lcci/03.05.Sort of Stacks/Solution.cpp
new file mode 100644
index 0000000000000..11aafbb6b2b8b
--- /dev/null
+++ b/lcci/03.05.Sort of Stacks/Solution.cpp
@@ -0,0 +1,44 @@
+class SortedStack {
+public:
+ SortedStack() {
+ }
+
+ void push(int val) {
+ stack t;
+ while (!stk.empty() && stk.top() < val) {
+ t.push(stk.top());
+ stk.pop();
+ }
+ stk.push(val);
+ while (!t.empty()) {
+ stk.push(t.top());
+ t.pop();
+ }
+ }
+
+ void pop() {
+ if (!isEmpty()) {
+ stk.pop();
+ }
+ }
+
+ int peek() {
+ return isEmpty() ? -1 : stk.top();
+ }
+
+ bool isEmpty() {
+ return stk.empty();
+ }
+
+private:
+ stack stk;
+};
+
+/**
+ * Your SortedStack object will be instantiated and called as such:
+ * SortedStack* obj = new SortedStack();
+ * obj->push(val);
+ * obj->pop();
+ * int param_3 = obj->peek();
+ * bool param_4 = obj->isEmpty();
+ */
\ No newline at end of file
diff --git a/lcci/03.05.Sort of Stacks/Solution.go b/lcci/03.05.Sort of Stacks/Solution.go
index 65f623a6147ab..ad0757b4103e3 100644
--- a/lcci/03.05.Sort of Stacks/Solution.go
+++ b/lcci/03.05.Sort of Stacks/Solution.go
@@ -1,37 +1,45 @@
type SortedStack struct {
- data []int
+ stk []int
}
func Constructor() SortedStack {
- return SortedStack{make([]int, 0)}
+ return SortedStack{}
}
-func (s *SortedStack) Push(val int) {
- temp := make([]int, 0)
- for !s.IsEmpty() && s.Peek() < val {
- temp = append(temp, s.Peek())
- s.Pop()
+func (this *SortedStack) Push(val int) {
+ t := make([]int, 0)
+ for len(this.stk) > 0 && this.stk[len(this.stk)-1] < val {
+ t = append(t, this.stk[len(this.stk)-1])
+ this.stk = this.stk[:len(this.stk)-1]
}
- s.data = append(s.data, val)
- for len(temp) > 0 {
- s.data = append(s.data, temp[len(temp)-1])
- temp = temp[:len(temp)-1]
+ this.stk = append(this.stk, val)
+ for i := len(t) - 1; i >= 0; i-- {
+ this.stk = append(this.stk, t[i])
}
}
-func (s *SortedStack) Pop() {
- if !s.IsEmpty() {
- s.data = s.data[:len(s.data)-1]
+func (this *SortedStack) Pop() {
+ if !this.IsEmpty() {
+ this.stk = this.stk[:len(this.stk)-1]
}
}
-func (s *SortedStack) Peek() int {
- if !s.IsEmpty() {
- return s.data[len(s.data)-1]
+func (this *SortedStack) Peek() int {
+ if this.IsEmpty() {
+ return -1
}
- return -1
+ return this.stk[len(this.stk)-1]
}
-func (s *SortedStack) IsEmpty() bool {
- return len(s.data) == 0
-}
\ No newline at end of file
+func (this *SortedStack) IsEmpty() bool {
+ return len(this.stk) == 0
+}
+
+/**
+ * Your SortedStack object will be instantiated and called as such:
+ * obj := Constructor();
+ * obj.Push(val);
+ * obj.Pop();
+ * param_3 := obj.Peek();
+ * param_4 := obj.IsEmpty();
+ */
\ No newline at end of file
diff --git a/lcci/03.05.Sort of Stacks/Solution.java b/lcci/03.05.Sort of Stacks/Solution.java
index 240a92d76010f..1ee1e3c31792f 100644
--- a/lcci/03.05.Sort of Stacks/Solution.java
+++ b/lcci/03.05.Sort of Stacks/Solution.java
@@ -1,32 +1,32 @@
class SortedStack {
- private Stack s;
+ private Deque stk = new ArrayDeque<>();
+
public SortedStack() {
- s = new Stack<>();
}
public void push(int val) {
- Stack t = new Stack<>();
- while (!isEmpty() && s.peek() < val) {
- t.push(s.pop());
+ Deque t = new ArrayDeque<>();
+ while (!stk.isEmpty() && stk.peek() < val) {
+ t.push(stk.pop());
}
- s.push(val);
+ stk.push(val);
while (!t.isEmpty()) {
- s.push(t.pop());
+ stk.push(t.pop());
}
}
public void pop() {
if (!isEmpty()) {
- s.pop();
+ stk.pop();
}
}
public int peek() {
- return isEmpty() ? -1 : s.peek();
+ return isEmpty() ? -1 : stk.peek();
}
public boolean isEmpty() {
- return s.isEmpty();
+ return stk.isEmpty();
}
}
diff --git a/lcci/03.05.Sort of Stacks/Solution.py b/lcci/03.05.Sort of Stacks/Solution.py
index 48787e320bce7..4183429856a67 100644
--- a/lcci/03.05.Sort of Stacks/Solution.py
+++ b/lcci/03.05.Sort of Stacks/Solution.py
@@ -1,21 +1,30 @@
class SortedStack:
+
def __init__(self):
- self.s = []
+ self.stk = []
def push(self, val: int) -> None:
t = []
- while not self.isEmpty() and self.s[-1] < val:
- t.append(self.s.pop())
- self.s.append(val)
- while len(t) > 0:
- self.s.append(t.pop())
+ while self.stk and self.stk[-1] < val:
+ t.append(self.stk.pop())
+ self.stk.append(val)
+ while t:
+ self.stk.append(t.pop())
def pop(self) -> None:
if not self.isEmpty():
- self.s.pop()
+ self.stk.pop()
def peek(self) -> int:
- return -1 if self.isEmpty() else self.s[-1]
+ return -1 if self.isEmpty() else self.stk[-1]
def isEmpty(self) -> bool:
- return len(self.s) == 0
+ return not self.stk
+
+
+# Your SortedStack object will be instantiated and called as such:
+# obj = SortedStack()
+# obj.push(val)
+# obj.pop()
+# param_3 = obj.peek()
+# param_4 = obj.isEmpty()
diff --git a/lcci/03.05.Sort of Stacks/Solution.rs b/lcci/03.05.Sort of Stacks/Solution.rs
index e3f9ae5bd62d5..917c648979c0e 100644
--- a/lcci/03.05.Sort of Stacks/Solution.rs
+++ b/lcci/03.05.Sort of Stacks/Solution.rs
@@ -1,43 +1,47 @@
use std::collections::VecDeque;
+
struct SortedStack {
- stack: VecDeque,
+ stk: VecDeque,
}
-/**
- * `&self` means the method takes an immutable reference.
- * If you need a mutable reference, change it to `&mut self` instead.
- */
impl SortedStack {
fn new() -> Self {
- Self { stack: VecDeque::new() }
+ SortedStack {
+ stk: VecDeque::new(),
+ }
}
fn push(&mut self, val: i32) {
- if self.is_empty() || self.peek() > val {
- self.stack.push_back(val);
- return;
+ let mut t = VecDeque::new();
+ while let Some(top) = self.stk.pop_back() {
+ if top < val {
+ t.push_back(top);
+ } else {
+ self.stk.push_back(top);
+ break;
+ }
+ }
+ self.stk.push_back(val);
+ while let Some(top) = t.pop_back() {
+ self.stk.push_back(top);
}
- let t = self.stack.pop_back().unwrap();
- self.push(val);
- self.stack.push_back(t);
}
fn pop(&mut self) {
- self.stack.pop_back();
+ if !self.is_empty() {
+ self.stk.pop_back();
+ }
}
fn peek(&self) -> i32 {
- *self.stack.back().unwrap_or(&-1)
+ if self.is_empty() {
+ -1
+ } else {
+ *self.stk.back().unwrap()
+ }
}
fn is_empty(&self) -> bool {
- self.stack.is_empty()
+ self.stk.is_empty()
}
-}/**
- * Your SortedStack object will be instantiated and called as such:
- * let obj = SortedStack::new();
- * obj.push(val);
- * obj.pop();
- * let ret_3: i32 = obj.peek();
- * let ret_4: bool = obj.is_empty();
- */
+}
diff --git a/lcci/03.05.Sort of Stacks/Solution.swift b/lcci/03.05.Sort of Stacks/Solution.swift
new file mode 100644
index 0000000000000..32f0232409d8e
--- /dev/null
+++ b/lcci/03.05.Sort of Stacks/Solution.swift
@@ -0,0 +1,40 @@
+class SortedStack {
+ private var stk: [Int] = []
+
+ init() {}
+
+ func push(_ val: Int) {
+ var temp: [Int] = []
+ while let top = stk.last, top < val {
+ temp.append(stk.removeLast())
+ }
+ stk.append(val)
+ while let last = temp.popLast() {
+ stk.append(last)
+ }
+ }
+
+ func pop() {
+ if !isEmpty() {
+ stk.removeLast()
+ }
+ }
+
+ func peek() -> Int {
+ return isEmpty() ? -1 : stk.last!
+ }
+
+ func isEmpty() -> Bool {
+ return stk.isEmpty
+ }
+}
+
+/**
+ * Your SortedStack object will be instantiated and called as such:
+ * let obj = new SortedStack();
+ * obj.push(val);
+ * obj.pop();
+ * let param_3 = obj.peek();
+ * var myVar: Bool;
+ * myVar = obj.isEmpty();
+ */
diff --git a/lcci/03.05.Sort of Stacks/Solution.ts b/lcci/03.05.Sort of Stacks/Solution.ts
index dab81b0c74459..1ed0aec93d832 100644
--- a/lcci/03.05.Sort of Stacks/Solution.ts
+++ b/lcci/03.05.Sort of Stacks/Solution.ts
@@ -1,30 +1,30 @@
class SortedStack {
- stack: number[];
- constructor() {
- this.stack = [];
- }
+ private stk: number[] = [];
+ constructor() {}
push(val: number): void {
- let t = [];
- while (!this.isEmpty() && this.peek() < val) {
- t.push(this.stack.pop());
+ const t: number[] = [];
+ while (this.stk.length > 0 && this.stk.at(-1)! < val) {
+ t.push(this.stk.pop()!);
}
- this.stack.push(val);
+ this.stk.push(val);
while (t.length > 0) {
- this.stack.push(t.pop());
+ this.stk.push(t.pop()!);
}
}
pop(): void {
- this.stack.pop();
+ if (!this.isEmpty()) {
+ this.stk.pop();
+ }
}
peek(): number {
- return this.isEmpty() ? -1 : this.stack[this.stack.length - 1];
+ return this.isEmpty() ? -1 : this.stk.at(-1)!;
}
isEmpty(): boolean {
- return this.stack.length == 0;
+ return this.stk.length === 0;
}
}
diff --git a/lcci/03.05.Sort of Stacks/Solution2.ts b/lcci/03.05.Sort of Stacks/Solution2.ts
deleted file mode 100644
index 3ca6e4c9c0eb2..0000000000000
--- a/lcci/03.05.Sort of Stacks/Solution2.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-class SortedStack {
- private stack: number[];
-
- constructor() {
- this.stack = [];
- }
-
- push(val: number): void {
- if (this.isEmpty() || this.peek() > val) {
- this.stack.push(val);
- return;
- }
-
- const tmp = this.stack.pop();
- this.push(val);
- this.stack.push(tmp);
- }
-
- pop(): void {
- this.stack.pop();
- }
-
- peek(): number {
- return this.stack[this.stack.length - 1] ?? -1;
- }
-
- isEmpty(): boolean {
- return this.stack.length === 0;
- }
-}
-
-/**
- * Your SortedStack object will be instantiated and called as such:
- * var obj = new SortedStack()
- * obj.push(val)
- * obj.pop()
- * var param_3 = obj.peek()
- * var param_4 = obj.isEmpty()
- */
diff --git a/lcci/03.06.Animal Shelter/README.md b/lcci/03.06.Animal Shelter/README.md
index a28d24ebe5d8a..e57fdbf8284bf 100644
--- a/lcci/03.06.Animal Shelter/README.md
+++ b/lcci/03.06.Animal Shelter/README.md
@@ -1,10 +1,19 @@
+---
+comments: true
+difficulty: 简单
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/03.06.Animal%20Shelter/README.md
+---
+
+
+
# [面试题 03.06. 动物收容所](https://leetcode.cn/problems/animal-shelter-lcci)
[English Version](/lcci/03.06.Animal%20Shelter/README_EN.md)
## 题目描述
-
+
+
动物收容所。有家动物收容所只收容狗与猫,且严格遵守“先进先出”的原则。在收养该收容所的动物时,收养人只能收养所有动物中“最老”(由其进入收容所的时间长短而定)的动物,或者可以挑选猫或狗(同时必须收养此类动物中“最老”的)。换言之,收养人不能自由挑选想收养的对象。请创建适用于这个系统的数据结构,实现各种操作方法,比如enqueue
、dequeueAny
、dequeueDog
和dequeueCat
。允许使用Java内置的LinkedList数据结构。
enqueue
方法有一个animal
参数,animal[0]
代表动物编号,animal[1]
代表动物种类,其中 0 代表猫,1 代表狗。
@@ -35,36 +44,50 @@
收纳所的最大容量为20000
+
+
## 解法
-### 方法一
+
+
+### 方法一:数组嵌套队列
+
+我们定义一个长度为 $2$ 的数组 $q$,用于存放猫和狗的队列。
+
+在 `enqueue` 操作中,假设动物编号为 $i$,动物种类为 $j$,我们将 $i$ 入队到 $q[j]$ 中。
+
+在 `dequeueAny` 操作中,我们判断 $q[0]$ 是否为空,或者 $q[1]$ 不为空且 $q[1][0] < q[0][0]$,如果是,则调用 `dequeueDog`,否则调用 `dequeueCat`。
+
+在 `dequeueDog` 操作中,如果 $q[1]$ 为空,则返回 $[-1, -1]$,否则返回 $[q[1].pop(), 1]$。
+
+在 `dequeueCat` 操作中,如果 $q[0]$ 为空,则返回 $[-1, -1]$,否则返回 $[q[0].pop(), 0]$。
+
+以上操作的时间复杂度均为 $O(1)$,空间复杂度为 $O(n)$,其中 $n$ 为动物收容所中动物的数量。
+#### Python3
+
```python
class AnimalShelf:
+
def __init__(self):
- self.cats = []
- self.dogs = []
+ self.q = [deque(), deque()]
def enqueue(self, animal: List[int]) -> None:
- if animal[1] == 0:
- self.cats.insert(0, animal[0])
- else:
- self.dogs.insert(0, animal[0])
+ i, j = animal
+ self.q[j].append(i)
def dequeueAny(self) -> List[int]:
- if len(self.dogs) == 0:
- return self.dequeueCat()
- if len(self.cats) == 0:
+ if not self.q[0] or (self.q[1] and self.q[1][0] < self.q[0][0]):
return self.dequeueDog()
- return self.dequeueDog() if self.dogs[-1] < self.cats[-1] else self.dequeueCat()
+ return self.dequeueCat()
def dequeueDog(self) -> List[int]:
- return [-1, -1] if len(self.dogs) == 0 else [self.dogs.pop(), 1]
+ return [-1, -1] if not self.q[1] else [self.q[1].popleft(), 1]
def dequeueCat(self) -> List[int]:
- return [-1, -1] if len(self.cats) == 0 else [self.cats.pop(), 0]
+ return [-1, -1] if not self.q[0] else [self.q[0].popleft(), 0]
# Your AnimalShelf object will be instantiated and called as such:
@@ -75,36 +98,33 @@ class AnimalShelf:
# param_4 = obj.dequeueCat()
```
+#### Java
+
```java
class AnimalShelf {
- Queue cats;
- Queue dogs;
+ private Deque[] q = new Deque[2];
+
public AnimalShelf() {
- cats = new LinkedList<>();
- dogs = new LinkedList<>();
+ Arrays.setAll(q, k -> new ArrayDeque<>());
}
public void enqueue(int[] animal) {
- if (animal[1] == 0) {
- cats.offer(animal[0]);
- } else {
- dogs.offer(animal[0]);
- }
+ q[animal[1]].offer(animal[0]);
}
public int[] dequeueAny() {
- return dogs.isEmpty()
- ? dequeueCat()
- : (cats.isEmpty() ? dequeueDog()
- : (dogs.peek() < cats.peek() ? dequeueDog() : dequeueCat()));
+ if (q[0].isEmpty() || (!q[1].isEmpty() && q[1].peek() < q[0].peek())) {
+ return dequeueDog();
+ }
+ return dequeueCat();
}
public int[] dequeueDog() {
- return dogs.isEmpty() ? new int[] {-1, -1} : new int[] {dogs.poll(), 1};
+ return q[1].isEmpty() ? new int[] {-1, -1} : new int[] {q[1].poll(), 1};
}
public int[] dequeueCat() {
- return cats.isEmpty() ? new int[] {-1, -1} : new int[] {cats.poll(), 0};
+ return q[0].isEmpty() ? new int[] {-1, -1} : new int[] {q[0].poll(), 0};
}
}
@@ -118,46 +138,138 @@ class AnimalShelf {
*/
```
-```ts
+#### C++
+
+```cpp
class AnimalShelf {
- private cats: number[];
- private dogs: number[];
+public:
+ AnimalShelf() {
+ }
- constructor() {
- this.cats = [];
- this.dogs = [];
+ void enqueue(vector animal) {
+ q[animal[1]].push(animal[0]);
}
+ vector dequeueAny() {
+ if (q[0].empty() || (!q[1].empty() && q[1].front() < q[0].front())) {
+ return dequeueDog();
+ }
+ return dequeueCat();
+ }
+
+ vector dequeueDog() {
+ if (q[1].empty()) {
+ return {-1, -1};
+ }
+ int dog = q[1].front();
+ q[1].pop();
+ return {dog, 1};
+ }
+
+ vector dequeueCat() {
+ if (q[0].empty()) {
+ return {-1, -1};
+ }
+ int cat = q[0].front();
+ q[0].pop();
+ return {cat, 0};
+ }
+
+private:
+ queue q[2];
+};
+
+/**
+ * Your AnimalShelf object will be instantiated and called as such:
+ * AnimalShelf* obj = new AnimalShelf();
+ * obj->enqueue(animal);
+ * vector param_2 = obj->dequeueAny();
+ * vector param_3 = obj->dequeueDog();
+ * vector param_4 = obj->dequeueCat();
+ */
+```
+
+#### Go
+
+```go
+type AnimalShelf struct {
+ q [2][]int
+}
+
+func Constructor() AnimalShelf {
+ return AnimalShelf{}
+}
+
+func (this *AnimalShelf) Enqueue(animal []int) {
+ this.q[animal[1]] = append(this.q[animal[1]], animal[0])
+}
+
+func (this *AnimalShelf) DequeueAny() []int {
+ if len(this.q[0]) == 0 || (len(this.q[1]) > 0 && this.q[0][0] > this.q[1][0]) {
+ return this.DequeueDog()
+ }
+ return this.DequeueCat()
+}
+
+func (this *AnimalShelf) DequeueDog() []int {
+ if len(this.q[1]) == 0 {
+ return []int{-1, -1}
+ }
+ dog := this.q[1][0]
+ this.q[1] = this.q[1][1:]
+ return []int{dog, 1}
+}
+
+func (this *AnimalShelf) DequeueCat() []int {
+ if len(this.q[0]) == 0 {
+ return []int{-1, -1}
+ }
+ cat := this.q[0][0]
+ this.q[0] = this.q[0][1:]
+ return []int{cat, 0}
+}
+
+/**
+ * Your AnimalShelf object will be instantiated and called as such:
+ * obj := Constructor();
+ * obj.Enqueue(animal);
+ * param_2 := obj.DequeueAny();
+ * param_3 := obj.DequeueDog();
+ * param_4 := obj.DequeueCat();
+ */
+```
+
+#### TypeScript
+
+```ts
+class AnimalShelf {
+ private q: number[][] = [[], []];
+ constructor() {}
+
enqueue(animal: number[]): void {
const [i, j] = animal;
- this[j === 0 ? 'cats' : 'dogs'].push(i);
+ this.q[j].push(i);
}
dequeueAny(): number[] {
- const n = this.dogs.length;
- const m = this.cats.length;
- if (n === 0 && m === 0) {
- return [-1, -1];
- }
- if ((this.dogs[0] ?? Infinity) < (this.cats[0] ?? Infinity)) {
- return [this.dogs.shift(), 1];
- } else {
- return [this.cats.shift(), 0];
+ if (this.q[0].length === 0 || (this.q[1].length > 0 && this.q[0][0] > this.q[1][0])) {
+ return this.dequeueDog();
}
+ return this.dequeueCat();
}
dequeueDog(): number[] {
- if (this.dogs.length === 0) {
+ if (this.q[1].length === 0) {
return [-1, -1];
}
- return [this.dogs.shift(), 1];
+ return [this.q[1].shift()!, 1];
}
dequeueCat(): number[] {
- if (this.cats.length === 0) {
+ if (this.q[0].length === 0) {
return [-1, -1];
}
- return [this.cats.shift(), 0];
+ return [this.q[0].shift()!, 0];
}
}
@@ -171,68 +283,97 @@ class AnimalShelf {
*/
```
+#### Rust
+
```rust
use std::collections::VecDeque;
struct AnimalShelf {
- cats: VecDeque,
- dogs: VecDeque,
+ q: [VecDeque; 2],
}
-/**
- * `&self` means the method takes an immutable reference.
- * If you need a mutable reference, change it to `&mut self` instead.
- */
impl AnimalShelf {
fn new() -> Self {
- Self {
- cats: VecDeque::new(),
- dogs: VecDeque::new(),
+ AnimalShelf {
+ q: [VecDeque::new(), VecDeque::new()],
}
}
fn enqueue(&mut self, animal: Vec) {
- if animal[1] == 0 {
- self.cats.push_back(animal[0]);
- } else {
- self.dogs.push_back(animal[0]);
- }
+ self.q[animal[1] as usize].push_back(animal[0]);
}
fn dequeue_any(&mut self) -> Vec {
- match (self.cats.is_empty(), self.dogs.is_empty()) {
- (true, true) => vec![-1, -1],
- (true, false) => self.dequeue_dog(),
- (false, true) => self.dequeue_cat(),
- (false, false) => {
- if self.dogs[0] < self.cats[0] { self.dequeue_dog() } else { self.dequeue_cat() }
- }
+ if self.q[0].is_empty()
+ || (!self.q[1].is_empty() && self.q[1].front().unwrap() < self.q[0].front().unwrap())
+ {
+ self.dequeue_dog()
+ } else {
+ self.dequeue_cat()
}
}
fn dequeue_dog(&mut self) -> Vec {
- if self.dogs.is_empty() {
- return vec![-1, -1];
+ if self.q[1].is_empty() {
+ vec![-1, -1]
+ } else {
+ let dog = self.q[1].pop_front().unwrap();
+ vec![dog, 1]
}
- vec![self.dogs.pop_front().unwrap(), 1]
}
fn dequeue_cat(&mut self) -> Vec {
- if self.cats.is_empty() {
- return vec![-1, -1];
+ if self.q[0].is_empty() {
+ vec![-1, -1]
+ } else {
+ let cat = self.q[0].pop_front().unwrap();
+ vec![cat, 0]
+ }
+ }
+}
+```
+
+#### Swift
+
+```swift
+class AnimalShelf {
+ private var q: [[Int]] = Array(repeating: [], count: 2)
+
+ init() {
+ }
+
+ func enqueue(_ animal: [Int]) {
+ q[animal[1]].append(animal[0])
+ }
+
+ func dequeueAny() -> [Int] {
+ if q[0].isEmpty || (!q[1].isEmpty && q[1].first! < q[0].first!) {
+ return dequeueDog()
}
- vec![self.cats.pop_front().unwrap(), 0]
+ return dequeueCat()
}
-}/**
+
+ func dequeueDog() -> [Int] {
+ return q[1].isEmpty ? [-1, -1] : [q[1].removeFirst(), 1]
+ }
+
+ func dequeueCat() -> [Int] {
+ return q[0].isEmpty ? [-1, -1] : [q[0].removeFirst(), 0]
+ }
+}
+
+/**
* Your AnimalShelf object will be instantiated and called as such:
- * let obj = AnimalShelf::new();
+ * let obj = new AnimalShelf();
* obj.enqueue(animal);
- * let ret_2: Vec = obj.dequeue_any();
- * let ret_3: Vec = obj.dequeue_dog();
- * let ret_4: Vec = obj.dequeue_cat();
+ * let param_2 = obj.dequeueAny();
+ * let param_3 = obj.dequeueDog();
+ * let param_4 = obj.dequeueCat();
*/
```
-
+
+
+
diff --git a/lcci/03.06.Animal Shelter/README_EN.md b/lcci/03.06.Animal Shelter/README_EN.md
index 1c30d258238c7..4a483da096a47 100644
--- a/lcci/03.06.Animal Shelter/README_EN.md
+++ b/lcci/03.06.Animal Shelter/README_EN.md
@@ -1,9 +1,19 @@
+---
+comments: true
+difficulty: Easy
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/03.06.Animal%20Shelter/README_EN.md
+---
+
+
+
# [03.06. Animal Shelter](https://leetcode.cn/problems/animal-shelter-lcci)
[中文文档](/lcci/03.06.Animal%20Shelter/README.md)
## Description
+
+
An animal shelter, which holds only dogs and cats, operates on a strictly"first in, first out" basis. People must adopt either the"oldest" (based on arrival time) of all animals at the shelter, or they can select whether they would prefer a dog or a cat (and will receive the oldest animal of that type). They cannot select which specific animal they would like. Create the data structures to maintain this system and implement operations such as enqueue
, dequeueAny
, dequeueDog
, and dequeueCat
. You may use the built-in Linked list data structure.
enqueue
method has a animal
parameter, animal[0]
represents the number of the animal, animal[1]
represents the type of the animal, 0 for cat and 1 for dog.
@@ -48,36 +58,50 @@
The number of animals in the shelter will not exceed 20000.
+
+
## Solutions
-### Solution 1
+
+
+### Solution 1: Array of Queues
+
+We define an array $q$ of length $2$ to store the queues of cats and dogs.
+
+In the `enqueue` operation, assuming the animal number is $i$ and the animal type is $j$, we enqueue $i$ into $q[j]$.
+
+In the `dequeueAny` operation, we check whether $q[0]$ is empty, or $q[1]$ is not empty and $q[1][0] < q[0][0]$. If so, we call `dequeueDog`, otherwise we call `dequeueCat`.
+
+In the `dequeueDog` operation, if $q[1]$ is empty, we return $[-1, -1]$, otherwise we return $[q[1].pop(), 1]$.
+
+In the `dequeueCat` operation, if $q[0]$ is empty, we return $[-1, -1]$, otherwise we return $[q[0].pop(), 0]$.
+
+The time complexity of the above operations is $O(1)$, and the space complexity is $O(n)$, where $n$ is the number of animals in the animal shelter.
+#### Python3
+
```python
class AnimalShelf:
+
def __init__(self):
- self.cats = []
- self.dogs = []
+ self.q = [deque(), deque()]
def enqueue(self, animal: List[int]) -> None:
- if animal[1] == 0:
- self.cats.insert(0, animal[0])
- else:
- self.dogs.insert(0, animal[0])
+ i, j = animal
+ self.q[j].append(i)
def dequeueAny(self) -> List[int]:
- if len(self.dogs) == 0:
- return self.dequeueCat()
- if len(self.cats) == 0:
+ if not self.q[0] or (self.q[1] and self.q[1][0] < self.q[0][0]):
return self.dequeueDog()
- return self.dequeueDog() if self.dogs[-1] < self.cats[-1] else self.dequeueCat()
+ return self.dequeueCat()
def dequeueDog(self) -> List[int]:
- return [-1, -1] if len(self.dogs) == 0 else [self.dogs.pop(), 1]
+ return [-1, -1] if not self.q[1] else [self.q[1].popleft(), 1]
def dequeueCat(self) -> List[int]:
- return [-1, -1] if len(self.cats) == 0 else [self.cats.pop(), 0]
+ return [-1, -1] if not self.q[0] else [self.q[0].popleft(), 0]
# Your AnimalShelf object will be instantiated and called as such:
@@ -88,36 +112,33 @@ class AnimalShelf:
# param_4 = obj.dequeueCat()
```
+#### Java
+
```java
class AnimalShelf {
- Queue cats;
- Queue dogs;
+ private Deque[] q = new Deque[2];
+
public AnimalShelf() {
- cats = new LinkedList<>();
- dogs = new LinkedList<>();
+ Arrays.setAll(q, k -> new ArrayDeque<>());
}
public void enqueue(int[] animal) {
- if (animal[1] == 0) {
- cats.offer(animal[0]);
- } else {
- dogs.offer(animal[0]);
- }
+ q[animal[1]].offer(animal[0]);
}
public int[] dequeueAny() {
- return dogs.isEmpty()
- ? dequeueCat()
- : (cats.isEmpty() ? dequeueDog()
- : (dogs.peek() < cats.peek() ? dequeueDog() : dequeueCat()));
+ if (q[0].isEmpty() || (!q[1].isEmpty() && q[1].peek() < q[0].peek())) {
+ return dequeueDog();
+ }
+ return dequeueCat();
}
public int[] dequeueDog() {
- return dogs.isEmpty() ? new int[] {-1, -1} : new int[] {dogs.poll(), 1};
+ return q[1].isEmpty() ? new int[] {-1, -1} : new int[] {q[1].poll(), 1};
}
public int[] dequeueCat() {
- return cats.isEmpty() ? new int[] {-1, -1} : new int[] {cats.poll(), 0};
+ return q[0].isEmpty() ? new int[] {-1, -1} : new int[] {q[0].poll(), 0};
}
}
@@ -131,46 +152,138 @@ class AnimalShelf {
*/
```
-```ts
+#### C++
+
+```cpp
class AnimalShelf {
- private cats: number[];
- private dogs: number[];
+public:
+ AnimalShelf() {
+ }
- constructor() {
- this.cats = [];
- this.dogs = [];
+ void enqueue(vector animal) {
+ q[animal[1]].push(animal[0]);
}
+ vector dequeueAny() {
+ if (q[0].empty() || (!q[1].empty() && q[1].front() < q[0].front())) {
+ return dequeueDog();
+ }
+ return dequeueCat();
+ }
+
+ vector dequeueDog() {
+ if (q[1].empty()) {
+ return {-1, -1};
+ }
+ int dog = q[1].front();
+ q[1].pop();
+ return {dog, 1};
+ }
+
+ vector dequeueCat() {
+ if (q[0].empty()) {
+ return {-1, -1};
+ }
+ int cat = q[0].front();
+ q[0].pop();
+ return {cat, 0};
+ }
+
+private:
+ queue q[2];
+};
+
+/**
+ * Your AnimalShelf object will be instantiated and called as such:
+ * AnimalShelf* obj = new AnimalShelf();
+ * obj->enqueue(animal);
+ * vector param_2 = obj->dequeueAny();
+ * vector param_3 = obj->dequeueDog();
+ * vector param_4 = obj->dequeueCat();
+ */
+```
+
+#### Go
+
+```go
+type AnimalShelf struct {
+ q [2][]int
+}
+
+func Constructor() AnimalShelf {
+ return AnimalShelf{}
+}
+
+func (this *AnimalShelf) Enqueue(animal []int) {
+ this.q[animal[1]] = append(this.q[animal[1]], animal[0])
+}
+
+func (this *AnimalShelf) DequeueAny() []int {
+ if len(this.q[0]) == 0 || (len(this.q[1]) > 0 && this.q[0][0] > this.q[1][0]) {
+ return this.DequeueDog()
+ }
+ return this.DequeueCat()
+}
+
+func (this *AnimalShelf) DequeueDog() []int {
+ if len(this.q[1]) == 0 {
+ return []int{-1, -1}
+ }
+ dog := this.q[1][0]
+ this.q[1] = this.q[1][1:]
+ return []int{dog, 1}
+}
+
+func (this *AnimalShelf) DequeueCat() []int {
+ if len(this.q[0]) == 0 {
+ return []int{-1, -1}
+ }
+ cat := this.q[0][0]
+ this.q[0] = this.q[0][1:]
+ return []int{cat, 0}
+}
+
+/**
+ * Your AnimalShelf object will be instantiated and called as such:
+ * obj := Constructor();
+ * obj.Enqueue(animal);
+ * param_2 := obj.DequeueAny();
+ * param_3 := obj.DequeueDog();
+ * param_4 := obj.DequeueCat();
+ */
+```
+
+#### TypeScript
+
+```ts
+class AnimalShelf {
+ private q: number[][] = [[], []];
+ constructor() {}
+
enqueue(animal: number[]): void {
const [i, j] = animal;
- this[j === 0 ? 'cats' : 'dogs'].push(i);
+ this.q[j].push(i);
}
dequeueAny(): number[] {
- const n = this.dogs.length;
- const m = this.cats.length;
- if (n === 0 && m === 0) {
- return [-1, -1];
- }
- if ((this.dogs[0] ?? Infinity) < (this.cats[0] ?? Infinity)) {
- return [this.dogs.shift(), 1];
- } else {
- return [this.cats.shift(), 0];
+ if (this.q[0].length === 0 || (this.q[1].length > 0 && this.q[0][0] > this.q[1][0])) {
+ return this.dequeueDog();
}
+ return this.dequeueCat();
}
dequeueDog(): number[] {
- if (this.dogs.length === 0) {
+ if (this.q[1].length === 0) {
return [-1, -1];
}
- return [this.dogs.shift(), 1];
+ return [this.q[1].shift()!, 1];
}
dequeueCat(): number[] {
- if (this.cats.length === 0) {
+ if (this.q[0].length === 0) {
return [-1, -1];
}
- return [this.cats.shift(), 0];
+ return [this.q[0].shift()!, 0];
}
}
@@ -184,68 +297,97 @@ class AnimalShelf {
*/
```
+#### Rust
+
```rust
use std::collections::VecDeque;
struct AnimalShelf {
- cats: VecDeque,
- dogs: VecDeque,
+ q: [VecDeque; 2],
}
-/**
- * `&self` means the method takes an immutable reference.
- * If you need a mutable reference, change it to `&mut self` instead.
- */
impl AnimalShelf {
fn new() -> Self {
- Self {
- cats: VecDeque::new(),
- dogs: VecDeque::new(),
+ AnimalShelf {
+ q: [VecDeque::new(), VecDeque::new()],
}
}
fn enqueue(&mut self, animal: Vec) {
- if animal[1] == 0 {
- self.cats.push_back(animal[0]);
- } else {
- self.dogs.push_back(animal[0]);
- }
+ self.q[animal[1] as usize].push_back(animal[0]);
}
fn dequeue_any(&mut self) -> Vec {
- match (self.cats.is_empty(), self.dogs.is_empty()) {
- (true, true) => vec![-1, -1],
- (true, false) => self.dequeue_dog(),
- (false, true) => self.dequeue_cat(),
- (false, false) => {
- if self.dogs[0] < self.cats[0] { self.dequeue_dog() } else { self.dequeue_cat() }
- }
+ if self.q[0].is_empty()
+ || (!self.q[1].is_empty() && self.q[1].front().unwrap() < self.q[0].front().unwrap())
+ {
+ self.dequeue_dog()
+ } else {
+ self.dequeue_cat()
}
}
fn dequeue_dog(&mut self) -> Vec {
- if self.dogs.is_empty() {
- return vec![-1, -1];
+ if self.q[1].is_empty() {
+ vec![-1, -1]
+ } else {
+ let dog = self.q[1].pop_front().unwrap();
+ vec![dog, 1]
}
- vec![self.dogs.pop_front().unwrap(), 1]
}
fn dequeue_cat(&mut self) -> Vec {
- if self.cats.is_empty() {
- return vec![-1, -1];
+ if self.q[0].is_empty() {
+ vec![-1, -1]
+ } else {
+ let cat = self.q[0].pop_front().unwrap();
+ vec![cat, 0]
+ }
+ }
+}
+```
+
+#### Swift
+
+```swift
+class AnimalShelf {
+ private var q: [[Int]] = Array(repeating: [], count: 2)
+
+ init() {
+ }
+
+ func enqueue(_ animal: [Int]) {
+ q[animal[1]].append(animal[0])
+ }
+
+ func dequeueAny() -> [Int] {
+ if q[0].isEmpty || (!q[1].isEmpty && q[1].first! < q[0].first!) {
+ return dequeueDog()
}
- vec![self.cats.pop_front().unwrap(), 0]
+ return dequeueCat()
}
-}/**
+
+ func dequeueDog() -> [Int] {
+ return q[1].isEmpty ? [-1, -1] : [q[1].removeFirst(), 1]
+ }
+
+ func dequeueCat() -> [Int] {
+ return q[0].isEmpty ? [-1, -1] : [q[0].removeFirst(), 0]
+ }
+}
+
+/**
* Your AnimalShelf object will be instantiated and called as such:
- * let obj = AnimalShelf::new();
+ * let obj = new AnimalShelf();
* obj.enqueue(animal);
- * let ret_2: Vec = obj.dequeue_any();
- * let ret_3: Vec = obj.dequeue_dog();
- * let ret_4: Vec = obj.dequeue_cat();
+ * let param_2 = obj.dequeueAny();
+ * let param_3 = obj.dequeueDog();
+ * let param_4 = obj.dequeueCat();
*/
```
-
+
+
+
diff --git a/lcci/03.06.Animal Shelter/Solution.cpp b/lcci/03.06.Animal Shelter/Solution.cpp
new file mode 100644
index 0000000000000..3d5d60769c964
--- /dev/null
+++ b/lcci/03.06.Animal Shelter/Solution.cpp
@@ -0,0 +1,46 @@
+class AnimalShelf {
+public:
+ AnimalShelf() {
+ }
+
+ void enqueue(vector animal) {
+ q[animal[1]].push(animal[0]);
+ }
+
+ vector dequeueAny() {
+ if (q[0].empty() || (!q[1].empty() && q[1].front() < q[0].front())) {
+ return dequeueDog();
+ }
+ return dequeueCat();
+ }
+
+ vector dequeueDog() {
+ if (q[1].empty()) {
+ return {-1, -1};
+ }
+ int dog = q[1].front();
+ q[1].pop();
+ return {dog, 1};
+ }
+
+ vector dequeueCat() {
+ if (q[0].empty()) {
+ return {-1, -1};
+ }
+ int cat = q[0].front();
+ q[0].pop();
+ return {cat, 0};
+ }
+
+private:
+ queue q[2];
+};
+
+/**
+ * Your AnimalShelf object will be instantiated and called as such:
+ * AnimalShelf* obj = new AnimalShelf();
+ * obj->enqueue(animal);
+ * vector param_2 = obj->dequeueAny();
+ * vector param_3 = obj->dequeueDog();
+ * vector param_4 = obj->dequeueCat();
+ */
\ No newline at end of file
diff --git a/lcci/03.06.Animal Shelter/Solution.go b/lcci/03.06.Animal Shelter/Solution.go
new file mode 100644
index 0000000000000..3bbd97765aa77
--- /dev/null
+++ b/lcci/03.06.Animal Shelter/Solution.go
@@ -0,0 +1,45 @@
+type AnimalShelf struct {
+ q [2][]int
+}
+
+func Constructor() AnimalShelf {
+ return AnimalShelf{}
+}
+
+func (this *AnimalShelf) Enqueue(animal []int) {
+ this.q[animal[1]] = append(this.q[animal[1]], animal[0])
+}
+
+func (this *AnimalShelf) DequeueAny() []int {
+ if len(this.q[0]) == 0 || (len(this.q[1]) > 0 && this.q[0][0] > this.q[1][0]) {
+ return this.DequeueDog()
+ }
+ return this.DequeueCat()
+}
+
+func (this *AnimalShelf) DequeueDog() []int {
+ if len(this.q[1]) == 0 {
+ return []int{-1, -1}
+ }
+ dog := this.q[1][0]
+ this.q[1] = this.q[1][1:]
+ return []int{dog, 1}
+}
+
+func (this *AnimalShelf) DequeueCat() []int {
+ if len(this.q[0]) == 0 {
+ return []int{-1, -1}
+ }
+ cat := this.q[0][0]
+ this.q[0] = this.q[0][1:]
+ return []int{cat, 0}
+}
+
+/**
+ * Your AnimalShelf object will be instantiated and called as such:
+ * obj := Constructor();
+ * obj.Enqueue(animal);
+ * param_2 := obj.DequeueAny();
+ * param_3 := obj.DequeueDog();
+ * param_4 := obj.DequeueCat();
+ */
\ No newline at end of file
diff --git a/lcci/03.06.Animal Shelter/Solution.java b/lcci/03.06.Animal Shelter/Solution.java
index d634369a3e221..89139660369b9 100644
--- a/lcci/03.06.Animal Shelter/Solution.java
+++ b/lcci/03.06.Animal Shelter/Solution.java
@@ -1,32 +1,27 @@
class AnimalShelf {
- Queue cats;
- Queue dogs;
+ private Deque[] q = new Deque[2];
+
public AnimalShelf() {
- cats = new LinkedList<>();
- dogs = new LinkedList<>();
+ Arrays.setAll(q, k -> new ArrayDeque<>());
}
public void enqueue(int[] animal) {
- if (animal[1] == 0) {
- cats.offer(animal[0]);
- } else {
- dogs.offer(animal[0]);
- }
+ q[animal[1]].offer(animal[0]);
}
public int[] dequeueAny() {
- return dogs.isEmpty()
- ? dequeueCat()
- : (cats.isEmpty() ? dequeueDog()
- : (dogs.peek() < cats.peek() ? dequeueDog() : dequeueCat()));
+ if (q[0].isEmpty() || (!q[1].isEmpty() && q[1].peek() < q[0].peek())) {
+ return dequeueDog();
+ }
+ return dequeueCat();
}
public int[] dequeueDog() {
- return dogs.isEmpty() ? new int[] {-1, -1} : new int[] {dogs.poll(), 1};
+ return q[1].isEmpty() ? new int[] {-1, -1} : new int[] {q[1].poll(), 1};
}
public int[] dequeueCat() {
- return cats.isEmpty() ? new int[] {-1, -1} : new int[] {cats.poll(), 0};
+ return q[0].isEmpty() ? new int[] {-1, -1} : new int[] {q[0].poll(), 0};
}
}
diff --git a/lcci/03.06.Animal Shelter/Solution.py b/lcci/03.06.Animal Shelter/Solution.py
index c391b53e16734..080b75f6b0715 100644
--- a/lcci/03.06.Animal Shelter/Solution.py
+++ b/lcci/03.06.Animal Shelter/Solution.py
@@ -1,26 +1,22 @@
class AnimalShelf:
+
def __init__(self):
- self.cats = []
- self.dogs = []
+ self.q = [deque(), deque()]
def enqueue(self, animal: List[int]) -> None:
- if animal[1] == 0:
- self.cats.insert(0, animal[0])
- else:
- self.dogs.insert(0, animal[0])
+ i, j = animal
+ self.q[j].append(i)
def dequeueAny(self) -> List[int]:
- if len(self.dogs) == 0:
- return self.dequeueCat()
- if len(self.cats) == 0:
+ if not self.q[0] or (self.q[1] and self.q[1][0] < self.q[0][0]):
return self.dequeueDog()
- return self.dequeueDog() if self.dogs[-1] < self.cats[-1] else self.dequeueCat()
+ return self.dequeueCat()
def dequeueDog(self) -> List[int]:
- return [-1, -1] if len(self.dogs) == 0 else [self.dogs.pop(), 1]
+ return [-1, -1] if not self.q[1] else [self.q[1].popleft(), 1]
def dequeueCat(self) -> List[int]:
- return [-1, -1] if len(self.cats) == 0 else [self.cats.pop(), 0]
+ return [-1, -1] if not self.q[0] else [self.q[0].popleft(), 0]
# Your AnimalShelf object will be instantiated and called as such:
diff --git a/lcci/03.06.Animal Shelter/Solution.rs b/lcci/03.06.Animal Shelter/Solution.rs
index 8c325e39ddf93..5e7490626d58f 100644
--- a/lcci/03.06.Animal Shelter/Solution.rs
+++ b/lcci/03.06.Animal Shelter/Solution.rs
@@ -1,59 +1,45 @@
use std::collections::VecDeque;
struct AnimalShelf {
- cats: VecDeque,
- dogs: VecDeque,
+ q: [VecDeque; 2],
}
-/**
- * `&self` means the method takes an immutable reference.
- * If you need a mutable reference, change it to `&mut self` instead.
- */
impl AnimalShelf {
fn new() -> Self {
- Self {
- cats: VecDeque::new(),
- dogs: VecDeque::new(),
+ AnimalShelf {
+ q: [VecDeque::new(), VecDeque::new()],
}
}
fn enqueue(&mut self, animal: Vec) {
- if animal[1] == 0 {
- self.cats.push_back(animal[0]);
- } else {
- self.dogs.push_back(animal[0]);
- }
+ self.q[animal[1] as usize].push_back(animal[0]);
}
fn dequeue_any(&mut self) -> Vec {
- match (self.cats.is_empty(), self.dogs.is_empty()) {
- (true, true) => vec![-1, -1],
- (true, false) => self.dequeue_dog(),
- (false, true) => self.dequeue_cat(),
- (false, false) => {
- if self.dogs[0] < self.cats[0] { self.dequeue_dog() } else { self.dequeue_cat() }
- }
+ if self.q[0].is_empty()
+ || (!self.q[1].is_empty() && self.q[1].front().unwrap() < self.q[0].front().unwrap())
+ {
+ self.dequeue_dog()
+ } else {
+ self.dequeue_cat()
}
}
fn dequeue_dog(&mut self) -> Vec {
- if self.dogs.is_empty() {
- return vec![-1, -1];
+ if self.q[1].is_empty() {
+ vec![-1, -1]
+ } else {
+ let dog = self.q[1].pop_front().unwrap();
+ vec![dog, 1]
}
- vec![self.dogs.pop_front().unwrap(), 1]
}
fn dequeue_cat(&mut self) -> Vec {
- if self.cats.is_empty() {
- return vec![-1, -1];
+ if self.q[0].is_empty() {
+ vec![-1, -1]
+ } else {
+ let cat = self.q[0].pop_front().unwrap();
+ vec![cat, 0]
}
- vec![self.cats.pop_front().unwrap(), 0]
}
-}/**
- * Your AnimalShelf object will be instantiated and called as such:
- * let obj = AnimalShelf::new();
- * obj.enqueue(animal);
- * let ret_2: Vec = obj.dequeue_any();
- * let ret_3: Vec = obj.dequeue_dog();
- * let ret_4: Vec = obj.dequeue_cat();
- */
+}
diff --git a/lcci/03.06.Animal Shelter/Solution.swift b/lcci/03.06.Animal Shelter/Solution.swift
new file mode 100644
index 0000000000000..7a78f0c570e8f
--- /dev/null
+++ b/lcci/03.06.Animal Shelter/Solution.swift
@@ -0,0 +1,35 @@
+class AnimalShelf {
+ private var q: [[Int]] = Array(repeating: [], count: 2)
+
+ init() {
+ }
+
+ func enqueue(_ animal: [Int]) {
+ q[animal[1]].append(animal[0])
+ }
+
+ func dequeueAny() -> [Int] {
+ if q[0].isEmpty || (!q[1].isEmpty && q[1].first! < q[0].first!) {
+ return dequeueDog()
+ }
+ return dequeueCat()
+ }
+
+ func dequeueDog() -> [Int] {
+ return q[1].isEmpty ? [-1, -1] : [q[1].removeFirst(), 1]
+ }
+
+ func dequeueCat() -> [Int] {
+ return q[0].isEmpty ? [-1, -1] : [q[0].removeFirst(), 0]
+ }
+}
+
+/**
+ * Your AnimalShelf object will be instantiated and called as such:
+ * let obj = new AnimalShelf();
+ * obj.enqueue(animal);
+ * let param_2 = obj.dequeueAny();
+ * let param_3 = obj.dequeueDog();
+ * let param_4 = obj.dequeueCat();
+ */
+
\ No newline at end of file
diff --git a/lcci/03.06.Animal Shelter/Solution.ts b/lcci/03.06.Animal Shelter/Solution.ts
index 88e7b7c5ab1e7..c7ff7ec236c38 100644
--- a/lcci/03.06.Animal Shelter/Solution.ts
+++ b/lcci/03.06.Animal Shelter/Solution.ts
@@ -1,42 +1,31 @@
class AnimalShelf {
- private cats: number[];
- private dogs: number[];
-
- constructor() {
- this.cats = [];
- this.dogs = [];
- }
+ private q: number[][] = [[], []];
+ constructor() {}
enqueue(animal: number[]): void {
const [i, j] = animal;
- this[j === 0 ? 'cats' : 'dogs'].push(i);
+ this.q[j].push(i);
}
dequeueAny(): number[] {
- const n = this.dogs.length;
- const m = this.cats.length;
- if (n === 0 && m === 0) {
- return [-1, -1];
- }
- if ((this.dogs[0] ?? Infinity) < (this.cats[0] ?? Infinity)) {
- return [this.dogs.shift(), 1];
- } else {
- return [this.cats.shift(), 0];
+ if (this.q[0].length === 0 || (this.q[1].length > 0 && this.q[0][0] > this.q[1][0])) {
+ return this.dequeueDog();
}
+ return this.dequeueCat();
}
dequeueDog(): number[] {
- if (this.dogs.length === 0) {
+ if (this.q[1].length === 0) {
return [-1, -1];
}
- return [this.dogs.shift(), 1];
+ return [this.q[1].shift()!, 1];
}
dequeueCat(): number[] {
- if (this.cats.length === 0) {
+ if (this.q[0].length === 0) {
return [-1, -1];
}
- return [this.cats.shift(), 0];
+ return [this.q[0].shift()!, 0];
}
}
diff --git a/lcci/04.01.Route Between Nodes/README.md b/lcci/04.01.Route Between Nodes/README.md
index 416d4a185f54f..2e3b752f019a6 100644
--- a/lcci/04.01.Route Between Nodes/README.md
+++ b/lcci/04.01.Route Between Nodes/README.md
@@ -1,10 +1,19 @@
+---
+comments: true
+difficulty: 中等
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/04.01.Route%20Between%20Nodes/README.md
+---
+
+
+
# [面试题 04.01. 节点间通路](https://leetcode.cn/problems/route-between-nodes-lcci)
[English Version](/lcci/04.01.Route%20Between%20Nodes/README_EN.md)
## 题目描述
-
+
+
节点间通路。给定有向图,设计一个算法,找出两个节点之间是否存在一条路径。
示例1:
@@ -27,56 +36,78 @@
图中可能存在自环和平行边。
+
+
## 解法
+
+
### 方法一:DFS
+我们先根据给定的图构建一个邻接表 $g$,其中 $g[i]$ 表示节点 $i$ 的所有邻居节点,用一个哈希表或数组 $vis$ 记录访问过的节点,然后从节点 $start$ 开始深度优先搜索,如果搜索到节点 $target$,则返回 `true`,否则返回 `false`。
+
+深度优先搜索的过程如下:
+
+1. 如果当前节点 $i$ 等于目标节点 $target$,返回 `true`;
+2. 如果当前节点 $i$ 已经访问过,返回 `false`;
+3. 否则,将当前节点 $i$ 标记为已访问,然后遍历节点 $i$ 的所有邻居节点 $j$,递归地搜索节点 $j$。
+
+时间复杂度 $(n + m)$,空间复杂度 $O(n + m)$。其中 $n$ 和 $m$ 分别是节点数量和边数量。
+
+#### Python3
+
```python
class Solution:
def findWhetherExistsPath(
self, n: int, graph: List[List[int]], start: int, target: int
) -> bool:
- def dfs(u):
- if u == target:
+ def dfs(i: int):
+ if i == target:
return True
- for v in g[u]:
- if v not in vis:
- vis.add(v)
- if dfs(v):
- return True
- return False
-
- g = defaultdict(list)
- for u, v in graph:
- g[u].append(v)
- vis = {start}
+ if i in vis:
+ return False
+ vis.add(i)
+ return any(dfs(j) for j in g[i])
+
+ g = [[] for _ in range(n)]
+ for a, b in graph:
+ g[a].append(b)
+ vis = set()
return dfs(start)
```
+#### Java
+
```java
class Solution {
+ private List[] g;
+ private boolean[] vis;
+ private int target;
+
public boolean findWhetherExistsPath(int n, int[][] graph, int start, int target) {
- Map> g = new HashMap<>();
+ vis = new boolean[n];
+ g = new List[n];
+ this.target = target;
+ Arrays.setAll(g, k -> new ArrayList<>());
for (int[] e : graph) {
- g.computeIfAbsent(e[0], k -> new ArrayList<>()).add(e[1]);
+ g[e[0]].add(e[1]);
}
- Set vis = new HashSet<>();
- vis.add(start);
- return dfs(start, target, g, vis);
+ return dfs(start);
}
- private boolean dfs(int u, int target, Map> g, Set vis) {
- if (u == target) {
+ private boolean dfs(int i) {
+ if (i == target) {
return true;
}
- for (int v : g.getOrDefault(u, Collections.emptyList())) {
- if (!vis.contains(v)) {
- vis.add(v);
- if (dfs(v, target, g, vis)) {
- return true;
- }
+ if (vis[i]) {
+ return false;
+ }
+ vis[i] = true;
+ for (int j : g[i]) {
+ if (dfs(j)) {
+ return true;
}
}
return false;
@@ -84,48 +115,58 @@ class Solution {
}
```
+#### C++
+
```cpp
class Solution {
public:
bool findWhetherExistsPath(int n, vector>& graph, int start, int target) {
- unordered_map> g;
- for (auto& e : graph) g[e[0]].push_back(e[1]);
- unordered_set vis{{start}};
- return dfs(start, target, g, vis);
- }
-
- bool dfs(int u, int& target, unordered_map>& g, unordered_set& vis) {
- if (u == target) return true;
- for (int& v : g[u]) {
- if (!vis.count(v)) {
- vis.insert(v);
- if (dfs(v, target, g, vis)) return true;
- }
+ vector g[n];
+ vector vis(n);
+ for (auto& e : graph) {
+ g[e[0]].push_back(e[1]);
}
- return false;
+ auto dfs = [&](this auto&& dfs, int i) -> bool {
+ if (i == target) {
+ return true;
+ }
+ if (vis[i]) {
+ return false;
+ }
+ vis[i] = true;
+ for (int j : g[i]) {
+ if (dfs(j)) {
+ return true;
+ }
+ }
+ return false;
+ };
+ return dfs(start);
}
};
```
+#### Go
+
```go
func findWhetherExistsPath(n int, graph [][]int, start int, target int) bool {
- g := map[int][]int{}
+ g := make([][]int, n)
+ vis := make([]bool, n)
for _, e := range graph {
- u, v := e[0], e[1]
- g[u] = append(g[u], v)
+ g[e[0]] = append(g[e[0]], e[1])
}
- vis := map[int]bool{start: true}
var dfs func(int) bool
- dfs = func(u int) bool {
- if u == target {
+ dfs = func(i int) bool {
+ if i == target {
return true
}
- for _, v := range g[u] {
- if !vis[v] {
- vis[v] = true
- if dfs(v) {
- return true
- }
+ if vis[i] {
+ return false
+ }
+ vis[i] = true
+ for _, j := range g[i] {
+ if dfs(j) {
+ return true
}
}
return false
@@ -134,53 +175,130 @@ func findWhetherExistsPath(n int, graph [][]int, start int, target int) bool {
}
```
+#### TypeScript
+
+```ts
+function findWhetherExistsPath(
+ n: number,
+ graph: number[][],
+ start: number,
+ target: number,
+): boolean {
+ const g: number[][] = Array.from({ length: n }, () => []);
+ const vis: boolean[] = Array.from({ length: n }, () => false);
+ for (const [a, b] of graph) {
+ g[a].push(b);
+ }
+ const dfs = (i: number): boolean => {
+ if (i === target) {
+ return true;
+ }
+ if (vis[i]) {
+ return false;
+ }
+ vis[i] = true;
+ return g[i].some(dfs);
+ };
+ return dfs(start);
+}
+```
+
+#### Swift
+
+```swift
+class Solution {
+ private var g: [[Int]]!
+ private var vis: [Bool]!
+ private var target: Int!
+
+ func findWhetherExistsPath(_ n: Int, _ graph: [[Int]], _ start: Int, _ target: Int) -> Bool {
+ vis = [Bool](repeating: false, count: n)
+ g = [[Int]](repeating: [], count: n)
+ self.target = target
+ for e in graph {
+ g[e[0]].append(e[1])
+ }
+ return dfs(start)
+ }
+
+ private func dfs(_ i: Int) -> Bool {
+ if i == target {
+ return true
+ }
+ if vis[i] {
+ return false
+ }
+ vis[i] = true
+ for j in g[i] {
+ if dfs(j) {
+ return true
+ }
+ }
+ return false
+ }
+}
+```
+
+
+
+
+
### 方法二:BFS
+与方法一类似,我们先根据给定的图构建一个邻接表 $g$,其中 $g[i]$ 表示节点 $i$ 的所有邻居节点,用一个哈希表或数组 $vis$ 记录访问过的节点,然后从节点 $start$ 开始广度优先搜索,如果搜索到节点 $target$,则返回 `true`,否则返回 `false`。
+
+时间复杂度 $(n + m)$,空间复杂度 $O(n + m)$。其中 $n$ 和 $m$ 分别是节点数量和边数量。
+
+#### Python3
+
```python
class Solution:
def findWhetherExistsPath(
self, n: int, graph: List[List[int]], start: int, target: int
) -> bool:
- g = defaultdict(list)
- for u, v in graph:
- g[u].append(v)
- q = deque([start])
+ g = [[] for _ in range(n)]
+ for a, b in graph:
+ g[a].append(b)
vis = {start}
+ q = deque([start])
while q:
- u = q.popleft()
- if u == target:
+ i = q.popleft()
+ if i == target:
return True
- for v in g[u]:
- if v not in vis:
- vis.add(v)
- q.append(v)
+ for j in g[i]:
+ if j not in vis:
+ vis.add(j)
+ q.append(j)
return False
```
+#### Java
+
```java
class Solution {
public boolean findWhetherExistsPath(int n, int[][] graph, int start, int target) {
- Map> g = new HashMap<>();
+ List[] g = new List[n];
+ Arrays.setAll(g, k -> new ArrayList<>());
+ boolean[] vis = new boolean[n];
for (int[] e : graph) {
- g.computeIfAbsent(e[0], k -> new ArrayList<>()).add(e[1]);
+ g[e[0]].add(e[1]);
}
Deque q = new ArrayDeque<>();
q.offer(start);
- Set vis = new HashSet<>();
- vis.add(start);
+ vis[start] = true;
while (!q.isEmpty()) {
- int u = q.poll();
- if (u == target) {
+ int i = q.poll();
+ if (i == target) {
return true;
}
- for (int v : g.getOrDefault(u, Collections.emptyList())) {
- if (!vis.contains(v)) {
- vis.add(v);
- q.offer(v);
+ for (int j : g[i]) {
+ if (!vis[j]) {
+ q.offer(j);
+ vis[j] = true;
}
}
}
@@ -189,22 +307,29 @@ class Solution {
}
```
+#### C++
+
```cpp
class Solution {
public:
bool findWhetherExistsPath(int n, vector>& graph, int start, int target) {
- unordered_map> g;
- for (auto& e : graph) g[e[0]].push_back(e[1]);
+ vector g[n];
+ vector vis(n);
+ for (auto& e : graph) {
+ g[e[0]].push_back(e[1]);
+ }
queue q{{start}};
- unordered_set vis{{start}};
+ vis[start] = true;
while (!q.empty()) {
- int u = q.front();
- if (u == target) return true;
+ int i = q.front();
q.pop();
- for (int v : g[u]) {
- if (!vis.count(v)) {
- vis.insert(v);
- q.push(v);
+ if (i == target) {
+ return true;
+ }
+ for (int j : g[i]) {
+ if (!vis[j]) {
+ q.push(j);
+ vis[j] = true;
}
}
}
@@ -213,25 +338,27 @@ public:
};
```
+#### Go
+
```go
func findWhetherExistsPath(n int, graph [][]int, start int, target int) bool {
- g := map[int][]int{}
+ g := make([][]int, n)
+ vis := make([]bool, n)
for _, e := range graph {
- u, v := e[0], e[1]
- g[u] = append(g[u], v)
+ g[e[0]] = append(g[e[0]], e[1])
}
q := []int{start}
- vis := map[int]bool{start: true}
+ vis[start] = true
for len(q) > 0 {
- u := q[0]
- if u == target {
+ i := q[0]
+ q = q[1:]
+ if i == target {
return true
}
- q = q[1:]
- for _, v := range g[u] {
- if !vis[v] {
- vis[v] = true
- q = append(q, v)
+ for _, j := range g[i] {
+ if !vis[j] {
+ vis[j] = true
+ q = append(q, j)
}
}
}
@@ -239,6 +366,40 @@ func findWhetherExistsPath(n int, graph [][]int, start int, target int) bool {
}
```
+#### TypeScript
+
+```ts
+function findWhetherExistsPath(
+ n: number,
+ graph: number[][],
+ start: number,
+ target: number,
+): boolean {
+ const g: number[][] = Array.from({ length: n }, () => []);
+ const vis: boolean[] = Array.from({ length: n }, () => false);
+ for (const [a, b] of graph) {
+ g[a].push(b);
+ }
+ const q: number[] = [start];
+ vis[start] = true;
+ while (q.length > 0) {
+ const i = q.pop()!;
+ if (i === target) {
+ return true;
+ }
+ for (const j of g[i]) {
+ if (!vis[j]) {
+ vis[j] = true;
+ q.push(j);
+ }
+ }
+ }
+ return false;
+}
+```
+
-
+
+
+
diff --git a/lcci/04.01.Route Between Nodes/README_EN.md b/lcci/04.01.Route Between Nodes/README_EN.md
index d454199ccce1b..e32e55d20a57b 100644
--- a/lcci/04.01.Route Between Nodes/README_EN.md
+++ b/lcci/04.01.Route Between Nodes/README_EN.md
@@ -1,9 +1,19 @@
+---
+comments: true
+difficulty: Medium
+edit_url: https://github.com/doocs/leetcode/edit/main/lcci/04.01.Route%20Between%20Nodes/README_EN.md
+---
+
+
+
# [04.01. Route Between Nodes](https://leetcode.cn/problems/route-between-nodes-lcci)
[中文文档](/lcci/04.01.Route%20Between%20Nodes/README.md)
## Description
+
+
Given a directed graph, design an algorithm to find out whether there is a route between two nodes.
Example1:
@@ -34,56 +44,78 @@
There might be self cycles and duplicated edges.
+
+
## Solutions
-### Solution 1
+
+
+### Solution 1: DFS
+
+First, we construct an adjacency list $g$ based on the given graph, where $g[i]$ represents all the neighboring nodes of node $i$. We use a hash table or array $vis$ to record the visited nodes, and then start a depth-first search from node $start$. If we search to node $target$, we return `true`, otherwise we return `false`.
+
+The process of depth-first search is as follows:
+
+1. If the current node $i$ equals the target node $target$, return `true`.
+2. If the current node $i$ has been visited, return `false`.
+3. Otherwise, mark the current node $i$ as visited, and then traverse all the neighboring nodes $j$ of node $i$, and recursively search node $j$.
+
+The time complexity is $O(n + m)$, and the space complexity is $O(n + m)$, where $n$ and $m$ are the number of nodes and edges respectively.
+#### Python3
+
```python
class Solution:
def findWhetherExistsPath(
self, n: int, graph: List[List[int]], start: int, target: int
) -> bool:
- def dfs(u):
- if u == target:
+ def dfs(i: int):
+ if i == target:
return True
- for v in g[u]:
- if v not in vis:
- vis.add(v)
- if dfs(v):
- return True
- return False
-
- g = defaultdict(list)
- for u, v in graph:
- g[u].append(v)
- vis = {start}
+ if i in vis:
+ return False
+ vis.add(i)
+ return any(dfs(j) for j in g[i])
+
+ g = [[] for _ in range(n)]
+ for a, b in graph:
+ g[a].append(b)
+ vis = set()
return dfs(start)
```
+#### Java
+
```java
class Solution {
+ private List[] g;
+ private boolean[] vis;
+ private int target;
+
public boolean findWhetherExistsPath(int n, int[][] graph, int start, int target) {
- Map> g = new HashMap<>();
+ vis = new boolean[n];
+ g = new List[n];
+ this.target = target;
+ Arrays.setAll(g, k -> new ArrayList<>());
for (int[] e : graph) {
- g.computeIfAbsent(e[0], k -> new ArrayList<>()).add(e[1]);
+ g[e[0]].add(e[1]);
}
- Set vis = new HashSet<>();
- vis.add(start);
- return dfs(start, target, g, vis);
+ return dfs(start);
}
- private boolean dfs(int u, int target, Map> g, Set vis) {
- if (u == target) {
+ private boolean dfs(int i) {
+ if (i == target) {
return true;
}
- for (int v : g.getOrDefault(u, Collections.emptyList())) {
- if (!vis.contains(v)) {
- vis.add(v);
- if (dfs(v, target, g, vis)) {
- return true;
- }
+ if (vis[i]) {
+ return false;
+ }
+ vis[i] = true;
+ for (int j : g[i]) {
+ if (dfs(j)) {
+ return true;
}
}
return false;
@@ -91,48 +123,58 @@ class Solution {
}
```
+#### C++
+
```cpp
class Solution {
public:
bool findWhetherExistsPath(int n, vector>& graph, int start, int target) {
- unordered_map> g;
- for (auto& e : graph) g[e[0]].push_back(e[1]);
- unordered_set vis{{start}};
- return dfs(start, target, g, vis);
- }
-
- bool dfs(int u, int& target, unordered_map>& g, unordered_set& vis) {
- if (u == target) return true;
- for (int& v : g[u]) {
- if (!vis.count(v)) {
- vis.insert(v);
- if (dfs(v, target, g, vis)) return true;
- }
+ vector