Solve four algorithm design tasks
Company: TikTok
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Take-home Project
Quick Answer: This multi-part question evaluates algorithm design and data-structure competencies including wildcard string pattern matching and trade-offs between dynamic programming and greedy strategies, dynamic pair-sum maintenance under frequent updates, O(1) LRU cache design, and scheduling/ordering for time-constrained threat neutralization.
Wildcard Pattern Matching
Constraints
- 0 <= len(s), len(p) <= 2000
- s contains only lowercase English letters
- p contains lowercase English letters, '?' and '*'
- The match must cover the entire input string
Examples
Input: ("aa", "a")
Expected Output: False
Explanation: The single 'a' in the pattern cannot cover the two-character string 'aa'.
Input: ("aa", "*")
Expected Output: True
Explanation: '*' matches any sequence, including 'aa'.
Hints
- Define dp[i][j] = does s[:i] match p[:j]. Base case dp[0][0] = True.
- A '*' in the pattern can either match no characters (dp[i][j-1]) or extend over one more character of s (dp[i-1][j]).
- Initialize the first row: a prefix of stars can match the empty string, so dp[0][j] = dp[0][j-1] when p[j-1] == '*'.
- The greedy alternative tracks the most recent '*' position and the last s-index it matched, so you can backtrack when a literal mismatch occurs.
Dynamic Pair-Sum Counter
Constraints
- 1 <= len(A), len(B) <= 1e5
- Up to 1e5 add/count operations combined
- For add: 0 <= i < len(B), and val keeps B[i] within integer range
- Element and total values fit in a 32-bit signed integer
Examples
Input: ([1, 1, 2, 3], [1, 4, 5, 2, 5, 4], [('count', 7), ('add', 3, 2), ('count', 8), ('count', 4)])
Expected Output: [4, 2, 1]
Explanation: count(7): a=2 pairs with the two 5s (2), a=3 pairs with the two 4s (2) -> 4. After add(3,2) B[3] becomes 4 so B has three 4s. count(8): a=3 + each 4 -> 3 pairs? a=3 needs 5 (two 5s)=2; a=2 needs 6=0 -> 2. count(4): a=2 needs 2 (B has one 2)=1.
Input: ([1, 2, 3], [1, 2, 3], [('count', 4)])
Expected Output: [3]
Explanation: (1,3),(2,2),(3,1) all sum to 4 -> 3 pairs.
Hints
- Keep a hash map of value -> frequency for B so each count is a sweep over A's distinct values with O(1) complement lookups.
- On add(i, val): decrement the count of the OLD B[i], mutate B[i], then increment the count of the NEW value. Never rescan B.
- Multiply A's value frequency by B's complement frequency to account for duplicate values on both sides.
- Iterate the array with fewer DISTINCT values (here A) during count to minimize work.
LRU Cache (O(1) get and put)
Constraints
- 1 <= cap <= 3000
- 0 <= key <= 1e4 (or arbitrary hashable keys)
- 0 <= value <= 1e5
- Up to 2e5 get/put operations
- Every get and put must be O(1)
Examples
Input: (2, [('put', 1, 1), ('put', 2, 2), ('get', 1), ('put', 3, 3), ('get', 2), ('put', 4, 4), ('get', 1), ('get', 3), ('get', 4)])
Expected Output: [1, -1, -1, 3, 4]
Explanation: get(1)=1 (and makes 1 MRU); put(3) evicts LRU key 2; get(2)=-1; put(4) evicts key 1; get(1)=-1; get(3)=3; get(4)=4.
Input: (1, [('put', 1, 1), ('get', 1), ('put', 2, 2), ('get', 1), ('get', 2)])
Expected Output: [1, -1, 2]
Explanation: Capacity 1: put(2) evicts key 1, so get(1)=-1 and get(2)=2.
Hints
- Pair a hash map (key -> node) with a doubly linked list ordered most- to least-recently used.
- On get/put of an existing key, unlink the node and move it to the most-recently-used end.
- When a put overflows capacity, evict the node at the least-recently-used end and delete its hash-map entry.
- A sentinel head and tail node removes all null-edge special cases in the linked list.
Max Threats Neutralized Before Breach
Constraints
- n == len(dist) == len(speed)
- 1 <= n <= 1e5
- 1 <= dist[i], speed[i] <= 1e5
- Use exact division (compare dist[i] vs t*speed[i] with integers to avoid floating error in production)
Examples
Input: ([1, 3, 4], [1, 1, 1])
Expected Output: 3
Explanation: Arrivals [1,3,4]. t=0:1>0 ok; t=1:3>1 ok; t=2:4>2 ok. All three neutralized.
Input: ([1, 1, 2, 3], [1, 1, 1, 1])
Expected Output: 1
Explanation: Arrivals [1,1,2,3]. t=0:1>0 ok (neutralize 1); t=1:1<=1 breach -> return 1.
Hints
- The arrival time of threat i is dist[i] / speed[i]; neutralize threats in increasing order of arrival.
- After sorting, the threat you handle at minute t (0-indexed) is the t-th earliest arriver.
- A breach occurs at minute t when arrival[t] <= t (it arrives before or exactly as you would act).
- If no breach happens through all n minutes, you neutralize every threat -> return n. To avoid float precision, compare dist[i] <= t * speed[i] with integers.