1047. Remove All Adjacent Duplicates In String
Leetcode: https://leetcode.com/problems/remove-all-adjacent-duplicates-in-string/
1 | def removeDuplicates(self, S: str) -> str: |
1209. Remove All Adjacent Duplicates in String II
Leetcode: https://leetcode.com/problems/remove-all-adjacent-duplicates-in-string-ii/
Brute Force: Count and remove
Time Complexity: O(n)
Space Complexity: O(1)
1 | def removeDuplicates(self, s: str, k: int) -> str: |
Memoized brute force
- Use an array to store repeating times of each character
1 | def removeDuplicates(self, s: str, k: int) -> str: |
Stack solution
- Build a stack for counts
- If the current character is the same as the one before, increment the count on the top of the stack. Else, push 1 to the stack
- If the count on the top of the stack equals k, erase last k characters and pop from the stack.
1 | def removeDuplicates(self, s: str, k: int) -> str: |
If we store both the count and the character in the stack, we do not have to modify the string. Instead, we can reconstruct the result from characters and counts in the stack.
Stack with Tree
654. Maximum Binary Tree
Leetcode: https://leetcode.com/problems/maximum-binary-tree/
1 | def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode: |
255. Verify Preorder Sequence in Binary Search Tree
Leetcode: https://leetcode.com/problems/verify-preorder-sequence-in-binary-search-tree/
Note:
- In preorder traversal, we first traverse left all the way to the leaf, during this process, the value is in a descending order. If the current number is larger than the
stack[-1]
, it means we reach to the right subtree - Then we start popping elements from stack, the last popped out element is the parent of the current element
- The parent would always smaller than the right subtree.
1 | def verifyPreorder(self, preorder): |
Parenthesis problems
32. Longest Valid Parentheses
Leetcode: https://leetcode.com/problems/longest-valid-parentheses/
[Solution]
- Scan the string from the beginning to end
- Use a stack to save all the unmatched parentheses
- If current character is ‘(‘, push its index to the stack. If current character is ‘)’ and the character at the index of the top of stack is ‘(‘, we just find a matching pair so pop from the stack. Otherwise, we push the index of ‘)’ to the stack.
- After the scan is done, the stack will only contain the indices of characters which cannot be matched. Then let’s use the opposite side - substring between adjacent indices should be valid parentheses.
- If the stack is empty, the whole input string is valid. Otherwise, we can scan the stack to get longest valid substring as described in step 3.
1 | def longestValidParentheses(self, s: 'str') -> 'int': |
678. Valid Parenthesis String
301. Remove Invalid Parentheses
Largest area problem
84. Largest Rectangle in Histogram
Leetcode: https://leetcode.com/problems/largest-rectangle-in-histogram/
85. Maximal Rectangle
Leetcode: https://leetcode.com/problems/maximal-rectangle/
Stack Sort Problem
- Ascending order stack:
- Used when
- Delete/skip k digits, find smallest
- remove larger element before nums[i]
if cur < stack[-1]: stack.pop(), stack.append(cur)
- Used when
739. Daily Temperatures
Leetcode: https://leetcode.com/problems/daily-temperatures/
Use a stack to store the index of elements. Use the stack to strictly store increasing temperatures.
1 | def dailyTemperatures(self, T: List[int]) -> List[int]: |
581. Shortest Unsorted Continuous Subarray
Leetcode: https://leetcode.com/problems/shortest-unsorted-continuous-subarray/
To find the left boundary, use a stack to keep track of all acsending sequence, once meet with a down slope, pop elements out untill the top of the stack is smaller than the element. Use the same way to find the right boundary.
1 | var findUnsortedSubarray = function(nums) { |
Note: Go forward to find the left boundary of unsorted elements, go backwards to find the right boundary of unsorted elements.
Time Complexity: O(N), Space: O(2N)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16def findUnsortedSubarray(self, nums: List[int]) -> int:
forward = []
backward = []
left, right = float('inf'), -1
for i in range(len(nums)):
j = len(nums) - i - 1
while forward and forward[-1][1] > nums[i]:
left = min(left, forward.pop()[0])
forward.append([i, nums[i]])
while backward and backward[-1][1] < nums[j]:
right = max(right, backward.pop()[0])
backward.append([j, nums[j]])
# ! Remember the case when nums is already sorted
if left == float('inf') and right == -1:
return 0
return right - left + 1
402. Remove K Digits
DP solution (TLE)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20def removeKdigits(self, num, k):
if k == 0 or len(num) < k:
return num
if k == len(num):
return "0"
n = len(num) - k
dp = [["0" for j in range(len(num))] for i in range(n + 1)]
for i in range(n + 1):
for j in range(len(num)):
if i == 0:
continue
if i > j:
dp[i][j] = num[:j + 1]
else:
if int(dp[i - 1][j - 1] + num[j]) > int(dp[i][j - 1]):
dp[i][j] = dp[i][j - 1]
else:
dp[i][j] = dp[i - 1][j - 1] + num[j]
# print(dp)
return dp[-1][-1]
Note:
- Beware of the cases when
k == len(num)
andk == 0
, andk > 0
after iteration - Always keep stack in acsending order
- Keep removing the previous digits that’s larger than the current digit while
k > 0
1 | def removeKdigits(self, num, k): |
901. Online Stock Span
Leetcode: https://leetcode.com/problems/online-stock-span/
Weighted decreasing stack, the weight represents number of elements skipped.
1 | class StockSpanner: |
316. Remove Duplicate Letters
Leetcode: https://leetcode.com/problems/remove-duplicate-letters/
Pretty Good Video: https://www.youtube.com/watch?v=SrlvMmfG8sA
1 | def removeDuplicateLetters(self, s: str) -> str: |
636. Exclusive Time of Functions
Leetcode: https://leetcode.com/problems/exclusive-time-of-functions/
Note:
- Use
prev
to remember the previous boundary
1 | def exclusiveTime(self, n: int, logs: List[str]) -> List[int]: |
1776. Car Fleet II
Leetcode: https://leetcode.com/problems/car-fleet-ii/
Idea: Similar to Car Fleet I, iterate from the last car, if A can’t catch B before B catch C, then C would be the next car A catch
1 | def getCollisionTimes(self, cars: List[List[int]]) -> List[float]: |
Optimize with stack: a stack of car indices where the collision time is strict decreasing.
1 | def getCollisionTimes(self, cars: List[List[int]]) -> List[float]: |