Skip to content

Commit 90341a4

Browse files
committed
Add some solutions to new problems
* 11. Container With Most Water * 131. Palindrome Partitioning * 237. Delete Node in a Linked List * 238. Product of Array Except Sefl * 31. Next Permutation * 334. Increasing Triplet Subsequence * 73. Set Matrix Zeroes * 56. Merge Intervals * 75. Sort Colors * 2095. Delete the Middle Node of a Linked List * 169. Majority Element * 128. Longest Consecutive Sequence * 148. Sort List
1 parent 7b55ad7 commit 90341a4

34 files changed

+1189
-106
lines changed

leetcode/101.symmetric-tree.md

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,34 @@ fun check(left: TreeNode?, right: TreeNode?): Boolean {
1515

1616
### Iterative
1717
```kotlin
18-
val emptyNode = TreeNode(-1)
18+
private val nullNode = TreeNode(200)
19+
1920
fun isSymmetric(root: TreeNode?): Boolean {
2021
if (root == null) return true
21-
val queue = ArrayDeque<TreeNode>()
22-
if (root.left != null) queue.addLast(root.left)
23-
if (root.right != null) queue.addLast(root.right)
24-
while (queue.isNotEmpty()) {
25-
val left = queue.removeFirst()
26-
if (queue.isEmpty()) return false
27-
val right = queue.removeFirst()
22+
23+
val leftQueue = ArrayDeque<TreeNode>()
24+
val rightQueue = ArrayDeque<TreeNode>()
25+
26+
leftQueue.addLast(if (root.left != null) root.left else nullNode)
27+
rightQueue.addLast(if (root.right != null) root.right else nullNode)
28+
29+
while (leftQueue.isNotEmpty() && rightQueue.isNotEmpty()) {
30+
val left = leftQueue.removeFirst()
31+
val right = rightQueue.removeFirst()
2832

29-
if (left == emptyNode && right == emptyNode) continue
30-
if (left == emptyNode || right == emptyNode || left.`val` != right.`val`) return false
31-
32-
// Make sure to enqueue empty node
33-
if (left.left != null) queue.addLast(left.left!!) else queue.addLast(emptyNode)
34-
if (right.right != null) queue.addLast(right.right!!) else queue.addLast(emptyNode)
35-
if (left.right != null) queue.addLast(left.right!!) else queue.addLast(emptyNode)
36-
if (right.left != null) queue.addLast(right.left!!) else queue.addLast(emptyNode)
33+
if (left.`val` != right.`val`) return false
34+
35+
if (left != nullNode) {
36+
leftQueue.addLast(if (left.left != null) left.left else nullNode)
37+
rightQueue.addLast(if (right.right != null) right.right else nullNode)
38+
}
39+
40+
if (right != nullNode) {
41+
leftQueue.addLast(if (left.right != null) left.right else nullNode)
42+
rightQueue.addLast(if (right.left != null) right.left else nullNode)
43+
}
3744
}
38-
return true
45+
46+
return leftQueue.isEmpty() && rightQueue.isEmpty()
3947
}
4048
```
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
## [11. Container With Most Water](https://leetcode.com/problems/container-with-most-water/)
2+
3+
The max area might come from the following choices:
4+
1. The widest
5+
2. The highest
6+
7+
But we don't know if we have the highest height at specific moment, but we can start the widest choice at first, we put `left` and `right` two pointers at the first and the last position, this forms the widest container, but it doesn't guarantee that it's highest, so we move the pointers to find the max area, but how to move?
8+
9+
```js
10+
[...8 ..... 6...]
11+
L -> <- R
12+
```
13+
14+
**Keep the higher one and move the shorter one!!**
15+
16+
* If we move `left` (to right direction), the width becomes smaller, then it's impossible to become the max area.
17+
* If we move `right` (to left direction), we *might* find the taller height later even if the width becomes smaller, it might be possible to find the max area.
18+
19+
So, we will move **the shorter-height** pointer!!
20+
21+
```js
22+
23+
24+
i: 0,1,2,3,4,5,6,7,8
25+
v: 1,8,6,2,5,4,8,3,7
26+
L R, min(1,7)*8, 8
27+
L R, min(8,7)*7, 49
28+
L R, min(8,3)*6, 18
29+
L R min(8,8)*5, 40
30+
L R min(6,8)*4, 24
31+
L R min(2,8)*3, 6
32+
L R min(5,8)*2, 10
33+
L R min(4,8)*1, 4
34+
35+
// Move right if the left == right
36+
L R min(8,4)*4, 16
37+
L R min(8,5)*3, 15
38+
L R min(8,2)*2, 4
39+
L R min(8,6)*1, 6
40+
```
41+
42+
```kotlin
43+
fun maxArea(height: IntArray): Int {
44+
var left = 0
45+
var right = height.size - 1
46+
var maxAmount = 0
47+
while (left < right) {
48+
val lowerHeight = min(height[left], height[right])
49+
val width = right - left
50+
maxAmount = max(maxAmount, lowerHeight * width)
51+
if (height[left] <= height[right]) {
52+
left++
53+
} else {
54+
right--
55+
}
56+
}
57+
return maxAmount
58+
}
59+
60+
// Sorting
61+
// Searching
62+
// Two Pointers
63+
// Sliding Windows
64+
// DP
65+
// Greedy
66+
```

leetcode/121.best-time-to-buy-and-sell-stock.md

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,18 @@
33
### Greedy
44
We're going to find minimium price to buy and calculate max profit for every day.
55

6-
| | Init | 7 | 1 | 5 | 3 | 6 | 4 |
7-
|-----------|------|---|---|---|---|---|---|
8-
| minPrice | oo | 7 | 1 | 1 | 1 | 1 | 1 |
9-
| maxProfit | 0 | 0 | 0 | 4 | 4 | 5 | 5 |
10-
116
```kotlin
127
fun maxProfit(prices: IntArray): Int {
13-
var min: Int? = null
14-
var profit = 0
15-
for (i in 0 until prices.size) {
16-
if (min == null) {
17-
min = prices[i]
8+
var lowestPrice = prices[0]
9+
var maxProfit = 0
10+
for (i in 1 until prices.size) {
11+
if (prices[i] < lowestPrice) {
12+
lowestPrice = prices[i]
1813
} else {
19-
if (prices[i] < min) min = prices[i]
20-
val currentProfit = prices[i] - min
21-
profit = if (currentProfit > profit) currentProfit else profit
14+
maxProfit = max(maxProfit, prices[i] - lowestPrice)
2215
}
2316
}
24-
return profit
17+
return maxProfit
2518
}
2619
```
2720

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
## [128. Longest Consecutive Sequence](https://leetcode.com/problems/longest-consecutive-sequence/)
2+
3+
For every number `x`, we can extend two side and check if `x - 1`, `x - 2`, ... and `x + 1`, `x + 2`, ... so on. But actually, we can check `x + 1`, `x + 2`, ... direction only, we've check if `x` is consecutive sequence when number is `x - 1`.
4+
5+
> https://leetcode.cn/problems/longest-consecutive-sequence/solution/zui-chang-lian-xu-xu-lie-by-leetcode-solution/
6+
7+
```kotlin
8+
fun longestConsecutive(nums: IntArray): Int {
9+
val hashSet = hashSetOf<Int>()
10+
for (num in nums) {
11+
hashSet.add(num)
12+
}
13+
14+
var maxStreak = 0
15+
for (i in 0 until nums.size) {
16+
val num = nums[i]
17+
// This is the key, we only check ascending direction.
18+
// If we have num - 1 which is consecutive to num, answer will check at num - 1 iteration, not current iteration.
19+
if (!hashSet.contains(num - 1)) {
20+
var next = num + 1
21+
while (hashSet.contains(next)) {
22+
next++
23+
}
24+
maxStreak = max(maxStreak, next - num)
25+
}
26+
}
27+
return maxStreak
28+
}
29+
```
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
## [131. Palindrome Partitioning](https://leetcode.com/problems/palindrome-partitioning)
2+
3+
```kotlin
4+
class Solution {
5+
6+
private val results = mutableListOf<List<String>>()
7+
8+
fun partition(s: String): List<List<String>> {
9+
val dp = findAllPalindromes(s)
10+
dfs(s, 0, mutableListOf<String>(), dp)
11+
return results
12+
}
13+
14+
private fun findAllPalindromes(s: String): Array<BooleanArray> {
15+
val dp = Array(s.length) { _ -> BooleanArray(s.length) }
16+
for (i in s.length - 1 downTo 0) {
17+
for (j in i until s.length) {
18+
if (i == j) dp[i][j] = true
19+
else if (j == i + 1) dp[i][j] = s[i] == s[j]
20+
else dp[i][j] = dp[i + 1][j - 1] && s[i] == s[j]
21+
}
22+
}
23+
return dp
24+
}
25+
26+
private fun dfs(s: String, startIndex: Int, partition: MutableList<String>, dp: Array<BooleanArray>) {
27+
if (startIndex == s.length) {
28+
results.add(ArrayList(partition))
29+
return
30+
}
31+
for (i in startIndex until s.length) {
32+
if (dp[startIndex][i]) {
33+
partition.add(s.substring(startIndex..i))
34+
dfs(s, i + 1, partition, dp)
35+
partition.removeAt(partition.size - 1)
36+
}
37+
}
38+
}
39+
}
40+
```
41+
42+
![](../media/131.palindrome-partitioning.jpg)

leetcode/141.linked-list-cycle.md

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,34 +24,27 @@ We can use two pointers approach to solve this with `O(1)` space:
2424
fun hasCycle(head: ListNode?): Boolean {
2525
var slow: ListNode? = head
2626
var fast: ListNode? = head
27+
// Make sure that fast pointer can move 2 steps
2728
while (fast != null && fast.next != null) {
2829
show = show?.next
2930
fast = fast?.next?.next
3031
if (fast == slow) return true
3132
}
3233
return false
3334
}
34-
```
35-
36-
For two pointers approach, there are some equivalent implementations:
3735

38-
> **Important**!! But we will choose above impelementation since it will affect the idea and result of [142. Linked List Cycle II](https://leetcode.com/problems/linked-list-cycle-ii/).
39-
40-
```kotlin
41-
/// Slow 1, fast 2
42-
// **Slow 2, fast 4
43-
// Slow 2, fast 4
44-
// **Slow 3, fast 3
45-
// Slow 3, fast 3
46-
//true
47-
fun hasCycle2(head: ListNode?): Boolean {
36+
// or
37+
fun hasCycle(head: ListNode?): Boolean {
38+
if (head == null || head?.next == null) return false
4839
var slow: ListNode? = head
4940
var fast: ListNode? = head?.next
50-
while (slow != null) {
51-
if (slow == fast) return true
52-
slow = slow.next
41+
while (slow != fast) {
42+
if (fast == null || fast?.next == null) return false
43+
slow = slow?.next
5344
fast = fast?.next?.next
5445
}
55-
return false
46+
return true
5647
}
5748
```
49+
50+
> Reference: Floyd’s Cycle-Finding Algorithm.

leetcode/148.sort-list.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
## [148. Sort List](https://leetcode.com/problems/sort-list)
2+
3+
### Merge Sort
4+
```kotlin
5+
fun sortList(head: ListNode?): ListNode? {
6+
return mergeSort(head)
7+
}
8+
9+
// Time Complexity: O(n lg n)
10+
// Space Complexity: O(lg n) for
11+
private fun mergeSort(head: ListNode?): ListNode? {
12+
if (head == null) return null
13+
if (head?.next == null) return head
14+
val middle = findMiddle(head)
15+
16+
// The head after merge sort might change, so we use updated head to merge.
17+
val newHead = mergeSort(head)
18+
val newMiddle = mergeSort(middle)
19+
return merge(newHead, newMiddle)
20+
}
21+
22+
private fun findMiddle(head: ListNode?): ListNode? {
23+
var previous: ListNode? = null
24+
var slow: ListNode? = head
25+
var fast: ListNode? = head
26+
while (fast != null && fast.next != null) {
27+
previous = slow
28+
slow = slow?.next
29+
fast = fast?.next?.next
30+
}
31+
previous?.next = null
32+
return slow
33+
}
34+
35+
private fun merge(head: ListNode?, middle: ListNode?): ListNode? {
36+
val sentinel = ListNode(-1)
37+
var n1: ListNode? = head
38+
var n2: ListNode? = middle
39+
var current: ListNode? = sentinel
40+
while (n1 != null && n2 != null) {
41+
if (n1.`val` <= n2.`val`) {
42+
current?.next = n1
43+
n1 = n1.next
44+
} else {
45+
current?.next = n2
46+
n2 = n2.next
47+
}
48+
current = current?.next
49+
}
50+
if (n1 != null) current?.next = n1
51+
if (n2 != null) current?.next = n2
52+
return sentinel.next
53+
}
54+
```
55+
56+
* **Time Complexity**: `O(n lg n)`.
57+
* **Space Complexity**: `O(lg n)` for recursive function calls.
58+
59+
60+
### Heap
61+
```kotlin
62+
private fun sortWithExtraSpace(head: ListNode?): ListNode? {
63+
val minHeap = PriorityQueue<ListNode>() { n1, n2 -> n1.`val` - n2.`val` }
64+
var node: ListNode? = head
65+
while (node != null) {
66+
val next = node.next
67+
node.next = null
68+
minHeap.add(node)
69+
node = next
70+
}
71+
72+
val sentinel = ListNode(-1)
73+
node = sentinel
74+
while (minHeap.isNotEmpty()) {
75+
node?.next = minHeap.poll()
76+
node = node?.next
77+
}
78+
return sentinel.next
79+
}
80+
```
81+
82+
* **Time Complexity**: `O(n lg n)`.
83+
* **Space Complexity**: `O(n)`.

0 commit comments

Comments
 (0)