Essentially, merely +- arithmetic operations and parenthesis (nested possible) need to be supported.
Concise & efficient Solution after refactoring
Upon second thought, it appears that stack operations are need only when destructing parenthesis and processing the +- operators (see also other shared solutions on LeetCode).
for ch in s: if ch.isdigit(): num = num * 10 + int(ch) elif ch == '(': # construct stack.append(sign) elif ch == ')': # destruct stack.pop() elif ch inset('+-'): res += sign * num # decide current sign based on parenthesis sign = (1if ch == '+'else -1) * stack[-1] num = 0# reset
return res + sign * num # remaining number
Intuitive Solution
It’s easier to come up with, but results in many edge cases to be taken care of, still likely ending up in TLE on LeetCode.
classSolution: defprocess_add_sub(self, nums, ops) -> int: ifnotlen(nums): return0 res = nums[0] # for idx, op in enumerate(ops, start=1): for idx inrange(1, len(ops) + 1): if idx >= len(nums): break op = ops[idx - 1] # print(f"process_add_sub {idx}:", (op, nums[idx])) res += -nums[idx] if op == '-'else nums[idx] return res
It was asked during a recent 60-min coding interview with OpusClip in early-July 2025, in which +-*/ arithmetic operations need to be supported.
Concise & efficient Solution after refactoring
Upon second thought, it appears that multiply and division operations are only needed when encountering an operator or reaching the end of the expression. Otherwise, simply proceed with adding/subtraction.
self.process_mul_div(nums, ops) return nums[0] + sum(-nums[idx + 1] if op == '-'else nums[idx + 1] \ for idx, op inenumerate(ops))
Intuitive Solution
Used in the original interview - it’s easier to come up with, but results in too many edge cases to be taken care of, so as to be difficult to complete in a timely manner during an interview.
# pass 2: add & subtract res, next_ptr = nums[0], 0 iflen(ops) > 0and ops[0][0] inset('*/'): res = new_nums[0][1] # use two-pointer to calculate the result for op, idx infilter(lambda op: op[0] inset('+-'), ops): while next_ptr < len(new_nums) and new_nums[next_ptr][0] < idx: next_ptr += 1 val = new_nums[next_ptr][1] if next_ptr < len(new_nums) and idx == new_nums[next_ptr][0] else nums[idx] res = add(res, val) if op == '+'else sub(res, val) return res
definsert(self, val: int) -> None: node = Node(val) # insert a node of value to the rear of the linked list self.rear.next = node self.rear = node # if self.head.next is None: # self.head.next = node
defdelete(self) -> None: # delete from head ifself.head.nextisnotNone: ifself.head == self.rear: self.rear = self.rear.next self.head = self.head.next
def__init__(self, capacity: int): # self.c pass
defget(self, key: int) -> int: pass
defput(self, key: int, value: int) -> None: pass
Test cases
The followings are the notes when asked by the interviewer to test the coding orally:
Originally asked during a 90-min offline coding round with Speechify in early-February 2025.
Requirement: Both most/least recently used nodes need to be accessed.
Learnings: Beware of the modularization and reusability to avoid running into unnecessary issues. When refreshing a node in the middle of a list, avoid mixing the head logic with the mid-node logic.
Note: No need to use dummy node like singly linked list.
Originally asked by Duolingo in early-February 2025.
Problem description:
1 2 3 4 5 6
There appears to be a certain data structure, together with trace logs of insertion and pop operations of element values into and out of it, but the type of the data structure is unknown.
The only known types of the data structure are as follows, which can be one type or more out of the following: Stack, queue, or priority queue (the minimum element gets popped out first)
Given the trace log as input, determine the potential type(s) of the data structure and output as a set of type strings. If none of the types applies, output an empty set.
Only minor typo occurred in implemenation during interview:
defdata_structure(trace): """ Returns: A set containing zero or more of the strings "stack", "queue", or "priority", indicating which data structures the trace can represent """ # edge case: empty iflen(trace) == 0: return {"stack", "queue", "priority"} # return {"stack", "queue"} # edge case: all inserts or all pops types = set([line[0] for line in trace]) if types == {'insert'} or types == {'pop'}: returnset() res = {'stack', 'queue', 'priority'} # assume it can be a stack and check for most number of elements in the data structure at any time stack = [] # num_elements = 0 for line, element in trace: if line == 'insert': stack.append(element) # num_elements += 1 elif line == 'pop'and (len(stack) == 0or element != stack[-1]): res.remove('stack') # not FILO; can't be a stack break elif line == 'pop': stack.pop() # FILO
from collections import deque que = deque() for line, element in trace: if line == 'insert': que.append(element) elif line == 'pop'andlen(que) == 0: res.remove('queue') break elif line == 'pop'andlen(que) > 0and que.popleft() != element: res.remove('queue') break elif line == 'pop'andlen(que) > 0: que.popleft() # FIFO # minimum heap - priority-queue from heapq import heappop, heappush min_heap = [] min_element = None for line, element in trace: if line == 'insert': heappush(min_heap, element) min_element = min(element, min_heap[0]) iflen(min_heap) > 0else element elif line == 'pop'andlen(min_heap) == 0: res.remove('priority') break elif line == 'pop'andlen(min_heap) > 0and min_heap[0] != min_element: res.remove('priority') break elif line == 'pop': heappop(min_heap)
Originally asked during a 60-min coding interview with Snap in mid-Jan 2025. The problem was so challenging that the proper solution wasn’t brought up until after about 40 minutes.
Problem Description:
1 2 3 4
Your old code in javascript has been preserved below.
Create a function convertUnits, to convert a number from a given starting unit to a given ending unit. You're given a list of conversion factors consisting of triple `(c, u, v)`, where `c` is a float and `u, v` are unit names.
from typing importOptional from collections import deque, defaultdict
defconvertUnits(c: float, u: str, v: str, factors: list[list]) -> Optional[float]: # build adjacency list using dictionary denoting the direct conversion factors of every unit adj_list: defaultdict[str, list[list]] = defaultdict(list) # DefaultDict[str, List[List[str, float]]] for factor in factors: rate: float = factor[0] unit1: str = factor[1] unit2: str = factor[2] # set up conversion list for both units adj_list[unit1].append([rate, unit2]) adj_list[unit2].append([1.0 / rate, unit1])
# perform BFS from u to v and calculate the overall rate visited: dict[str, float] = { u: 1.0 } que: deque[str] = deque() que.append(u) whilelen(que) and v notin visited: cur_unit = que.popleft() for factor in adj_list.get(cur_unit, []): next_rate: float = factor[0] next_unit: str = factor[1] if next_unit in visited: continue visited[next_unit] = visited[cur_unit] * next_rate que.append(next_unit)
const convertUnits = ( c: number, u: string, v: string, factors: Array<[number, string, string]> ): number => { varratio: number = 1.0; varconversion: Map<string, number> = newMap(); varadj: string[] = []; // key: Array<u, v> -> value: ratio number
// parse the ratios for (const factor of factors) { var pair1 = [factor[1], factor[2]].join(""); var pair2 = [factor[2], factor[1]].join(""); conversion[pair1] = factor[0]; conversion[pair2] = 1.0 / factor[0]; adj.append(pair1); adj.append(pair2); } // combine the ratios for (const factor1 of factors) { for (const factor2 of factors) { if (factor1[1] === factor2[2]) { // check overlapping units var pair1 = [factor1[2], factor2[1]].join(""); var pair2 = [factor2[1], factor1[2]].join(""); var rate = factor1[0] * factor2[0]; conversion[pair1] = factor1[0] * factor2[0]; conversion[pair2] = 1.0 / rate; } // || factor1[2] === factor2[1] } }
// breath-first search using queue varque: string[] = [u]; while (que.length > 0) { var top = que[0]; que.shift(); for (const factor in conversion) { } } return ratio * c; };