Stack and Queue Questions Part 1
173. Print elements of a linked list
def print_linked_list_in_reverse(head):
nodes = []
while head:
nodes.append(head.data)
head = head.next
while nodes:
print(nodes.pop())
174. (LC 155) Min Stack
155. Min Stack Medium
Solution 1 [10] [7] T O(1), S O(N)
class MinStack:
def __init__(self):
self.stack = []
self.minStack = []
def push(self, val: int) -> None:
self.stack.append(val)
val = min(val, self.minStack[-1] if self.minStack else val)
self.minStack.append(val)
def pop(self) -> None:
self.stack.pop()
self.minStack.pop()
def top(self) -> int:
return self.stack[-1]
def getMin(self) -> int:
return self.minStack[-1]
175. (LC 150) Evaluate Reverse Polish Notation
LC 150. Evaluate Reverse Polish Notation Medium
tokens = ["2","1","+","3","*"]tokens = ["4","13","5","/","+"]Recall: passing args to lambda
a = lambda x, y: x + y print(a(2, 3))
Solution 1 [2] (LC accepted 95,85%)
stack = [] # intermidiate results
DELIMITER = ","
OPERATORS = {
"+": lambda x, y: x + y,
"-": lambda x, y: y - x,
"*": lambda y, x: x * y,
"/": lambda x, y: int(y / x),
}
for token in tokens.split(DELIMITER):
if token in OPERATORS:
stack.append(OPERATORS[token](stack.pop(), stack.pop()))
else: # token is a num
stack.append(int(token))
return stack[-1]
Solution 2 [7]
import operator
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
opt = {
"+": operator.add,
"-": operator.sub,
"*": operator.mul,
"/": operator.truediv,
}
s = []
for token in tokens:
if token in opt:
s.append(int(opt[token](s.pop(-2), s.pop(-1))))
else:
s.append(int(token))
return s[0]
Solution 3 [10] O(N)
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
stack = []
for c in tokens:
if c == "+":
stack.append(stack.pop() + stack.pop())
elif c == "-":
a, b = stack.pop(), stack.pop()
stack.append(b - a)
elif c == "*":
stack.append(stack.pop() * stack.pop())
elif c == "/":
a, b = stack.pop(), stack.pop()
stack.append(int(float(b) / a))
else:
stack.append(int(c))
return stack[0]
My V (LC accepted 48,85%)
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
operators = {'+': operator.add, '-': operator.sub,
'*': operator.mul, '/': operator.truediv}
stack = []
for s in tokens:
if s in operators:
val1 = stack.pop()
val2 = stack.pop()
val3 = operators[s](val2, val1)
stack.append(int(val3))
else:
stack.append(int(s))
return stack[0]
176. (LC 71) Simplify Path
71. Simplify Path Medium
Our new path IS STACK itself (stack is not a helper data structure).
Solution 1
class Solution:
def simplifyPath(self, path: str) -> str:
stack = []
for i in path.split("/"):
# if i == "/" or i == '//', it becomes '' (empty string)
if i == "..":
if stack:
stack.pop()
elif i == "." or i == '':
# skip "." or an empty string
continue
else:
stack.append(i)
res = "/" + "/".join(stack)
return res
'':>>> path = '/../ed//tr/'
>>> L = path.split("/")
>>> L
['', '..', 'ed', '', 'tr', '']
stack = ['ed', 'tr']My V (LC accepted 85, 37%)
class Solution:
def simplifyPath(self, path: str) -> str:
stack = []
path = path.split('/')
for p in path:
if p == '.':
continue
elif p == '..':
if stack:
stack.pop()
elif p != '/' and p != '':
stack.append(p)
new_path = '/'.join(stack)
return '/' + new_path
177. (LC 22) Generate Parentheses
22. Generate Parentheses Medium
Backtracking is an algorithmic technique whose goal is to use brute force to find all solutions to a problem. It entails gradually compiling a set of all possible solutions. Because a problem will have constraints, solutions that do not meet them will be removed.
A backtracking algorithm uses the depth-first search method. If a proposed solution satisfies the constraints, it will keep looking. If it does not, the branch is removed, and <the algorithm returns to the previous level>.
State-Space Tree A tree that represents all of the possible states of the problem, from the root as an initial state to the leaf as a terminal state.
Intermediate checkpoints. If the checkpoints do not lead to a viable solution, the problem can return to the checkpoints and take another path to find a solution.
Backtracking boilerplate:
void FIND_SOLUTIONS(parameters):
if (valid solution):
store the solution
Return
for (all choice):
if (valid choice):
APPLY (choice)
FIND_SOLUTIONS (parameters)
BACKTRACK (remove choice) <===
Return
Use variable <cur> where you build a current valid string
Solution 2 (rewrite from C, LC accepted 30, 15%, 2nd run 70, 80)
class Solution:
def generateParenthesis(self, n: int) -> List[str]:
cur = ''
res = []
def backtrack(cur, o, c):
if o == n == c:
res.append(cur)
return
# add open par
if o < n:
backtrack(cur + '(', o+1, c)
# add closed
if o > c:
backtrack(cur + ')', o, c+1)
backtrack(cur, 0,0)
return res
Solution 1
class Solution:
def generateParenthesis(self, n: int) -> List[str]:
stack = []
res = []
def backtrack(openN, closedN):
if openN == closedN == n:
res.append("".join(stack))
return
if openN < n:
stack.append("(")
backtrack(openN + 1, closedN)
stack.pop()
if closedN < openN:
stack.append(")")
backtrack(openN, closedN + 1)
stack.pop()
backtrack(0, 0)
return res
178. (LC 739) Daily Temperatures
739. Daily Temperatures Medium
Solution 1 [10]
class Solution:
def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
res = [0] * len(temperatures) #1
stack = [] # pair: [temp, index]
for i, t in enumerate(temperatures):
while stack and t > stack[-1][0]:
poppedT, poppedInd = stack.pop()
res[stackInd] = i - stackInd
stack.append((t, i))
return res
stack=[(74,1)]
stack=[(75,2)]
179. (LC 853) Car Fleet
853. Car Fleet Medium
class Solution:
def carFleet(self, target: int, position: List[int], speed: List[int]) -> int:
time = [0] * len(position)
cars = [0] * len(position)
for i in range(len(position)):
time[i] = (target - position[i]) / speed[i]
cars[i] = (position[i], time[i])
cars.sort()
fleet = 0
prev_time = 0
while cars:
p,t = cars.pop()
if t > prev_time:
fleet +=1
prev_time = t #update only if found greater time
return fleet
Solution [10]
def carFleet(target: int, position: List[int], speed: List[int]) -> int:
pair = [(p, s) for p, s in zip(position, speed)]
pair.sort(reverse=True)
stack = [] #[time1, time2..]
for p, s in pair: # Reverse Sorted Order
stack.append((target - p) / s) #**
if len(stack) >= 2 and stack[-1] <= stack[-2]:
stack.pop()
return len(stack)
#** - Unlike many algs where we put to stack as last step, here we first put to stack, and work with values stack[-1], stack[-2], because otherwise we don’t check if to merge the last car into a fleet with previous cars.
C++
class Solution {
public:
int carFleet(int target, vector<int>& position, vector<int>& speed) {
vector<vector<double>> cars;
for(size_t i = 0; i != position.size(); ++i){
double t = (target - position[i]) / static_cast<double>(speed[i]);
cars.push_back({static_cast<double>(position[i]), t});
}
sort(cars.begin(), cars.end());
int fleet = 0;
double prev_time = 0;
while (!cars.empty()){
double t = cars.back()[1];
cars.pop_back();
if(t > prev_time){
++fleet;
prev_time = t;
}
}
return fleet;
}
};
180. (LC 84) Largest Rectangle in Histogram
84. Largest Rectangle in Histogram Hard
# stk=[(1,0),(5,2),(6,3)], next v=2, after popping stk=[(1,0),(2,3)]
# ^
My V (LC accepted 35, 30%)
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
ans = 0
stack = [] #[index, height]
for i, h in enumerate(heights):
start = i
while stack and stack[-1][1] > h:
index, height = stack.pop()
area = height * (i-index)
ans = max(ans, area)
start = index
stack.append([start, h])
for i, h in stack:
area = h * (len(heights) - i)
ans = max(ans, area)
return ans
My V2 (LC accepted 30, 42%)
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
stack = [] #[(v,i),..] mono increasing
area = 0
for i, n in enumerate(heights):
if not stack or stack[-1][0] <= n:
stack.append((n,i))
else:
while stack and stack[-1][0] > n:
v, ind = stack.pop()
area = max(area, (i-ind)*v)
stack.append((n, ind)) #append to stack with last popped index
index=len(heights)
while stack:
v,ind = stack.pop()
area = max(area, v*(index-ind))
return area
Solution 1 [10]
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
maxArea = 0
stack = [] # pair: (index, height)
for i, h in enumerate(heights):
start = i #**1
while stack and stack[-1][1] > h:
index, height = stack.pop()
maxArea = max(maxArea, height * (i - index))
start = index #**1
stack.append((start, h))
for i, h in stack: #**2
maxArea = max(maxArea, h * (len(heights) - i))
return maxArea
# 3
# 2 3
# 1 2 3
E.g.: Area of rect 1 = 1 * ((len=3) - index=0) = 3
C++
//My V (LC accepted 65, 55%)
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
stack<pair<int,int>> stk; //{{val, index},..}
int area {0};
for(int i=0; i!=heights.size(); ++i){
int n = heights.at(i);
if(stk.empty() || stk.top().first <= n)
stk.push({n,i});
else{
int ind{0}; //have to declare not in while, otherwise stays in while locally
while(!stk.empty() && stk.top().first > n){
ind = stk.top().second;
int v = stk.top().first;
stk.pop();
area = max(area, v * (i-ind));
}
stk.push({n, ind});
}
}
int index = heights.size();
while(!stk.empty()){
int ind = stk.top().second, v = stk.top().first;
stk.pop();
area = max(area, v * (index-ind));
}
return area;
}
};