Solve multiple algorithmic interview questions
Company: Capital One
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: hard
Interview Round: Take-home Project
This multi-part prompt evaluates algorithmic problem-solving and core data-structure competencies such as array manipulation, modular/date arithmetic, matrix transformations, dynamic set and interval maintenance, string concatenation frequency counting, and path-based expression evaluation on grids.
Company: Capital One
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: hard
Interview Round: Take-home Project
Loading coding console...
Quick Answer: This multi-part prompt evaluates algorithmic problem-solving and core data-structure competencies such as array manipulation, modular/date arithmetic, matrix transformations, dynamic set and interval maintenance, string concatenation frequency counting, and path-based expression evaluation on grids.
Input: (3, [4, 2, 5, 3, 1])
Expected Output: 'tie'
Explanation: There are two values greater than 3 and two values smaller than 3.
Input: (0, [-1, 1, 2])
Expected Output: 'greater'
Explanation: Two values are greater than 0, while one is smaller.
Input: (5, [1, 2, 3])
Expected Output: 'smaller'
Explanation: All values are smaller than 5.
Input: (7, [])
Expected Output: 'tie'
Explanation: Both counts are zero for an empty array.
def solution(target, arr):
greater = sum(1 for x in arr if x > target)
smaller = sum(1 for x in arr if x < target)
if greater > smaller:
return 'greater'
if smaller > greater:
return 'smaller'
return 'tie'
Time complexity: O(n). Space complexity: O(1).
Input: (0, 1, 1)
Expected Output: 0
Explanation: January 1 has the initial state.
Input: (7, 1, 2)
Expected Output: 0
Explanation: One day later, state 7 advances to 0.
Input: (3, 3, 1)
Expected Output: 6
Explanation: 59 days have passed before March 1, so the state is (3 + 59) mod 8 = 6.
Input: (5, 12, 31)
Expected Output: 1
Explanation: December 31 is 364 days after January 1 in a non-leap year.
def solution(initial_state, month, day):
month_lengths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
offset = sum(month_lengths[:month - 1]) + day - 1
return (initial_state + offset) % 8
Time complexity: O(1). Space complexity: O(1).
Input: ([[1, 2], [3, 4]], ['reverseRow 0', 'swap 0 1'])
Expected Output: [[3, 4], [2, 1]]
Explanation: Reverse the first row to get [2,1], then swap the two rows.
Input: ([[1, 2, 3], [4, 5, 6]], ['rotate'])
Expected Output: [[4, 1], [5, 2], [6, 3]]
Explanation: A 2x3 matrix becomes a 3x2 matrix after one clockwise rotation.
Input: ([[1, 2], [3, 4], [5, 6]], ['rotate', 'swap 0 1'])
Expected Output: [[6, 4, 2], [5, 3, 1]]
Explanation: Rotate first, then swap the first two rows of the rotated matrix.
Input: ([[7]], ['rotate', 'reverseRow 0'])
Expected Output: [[7]]
Explanation: A 1x1 matrix stays the same.
def solution(grid, commands):
grid = [row[:] for row in grid]
for command in commands:
parts = command.split()
if parts[0] == 'reverseRow':
r = int(parts[1])
grid[r].reverse()
elif parts[0] == 'swap':
r1 = int(parts[1])
r2 = int(parts[2])
grid[r1], grid[r2] = grid[r2], grid[r1]
elif parts[0] == 'rotate':
if not grid:
grid = []
else:
grid = [list(row) for row in zip(*grid[::-1])]
return grid
Time complexity: O(total work done by commands). Space complexity: O(number of cells) for rotation output.
Input: ([2, 3, 0, 4],)
Expected Output: [1, 2, 2, 3]
Explanation: After each insertion, the best sequence lengths are 1, 2, 2, and 3.
Input: ([1, 1, 1],)
Expected Output: [1, 1, 1]
Explanation: Duplicates do not increase the longest consecutive length.
Input: ([],)
Expected Output: []
Explanation: Empty input gives an empty output.
Input: ([100, 4, 200, 1, 3, 2],)
Expected Output: [1, 1, 1, 1, 2, 4]
Explanation: The last insertion connects 1,2,3,4 into a length-4 sequence.
def solution(nums):
lengths = {}
seen = set()
best = 0
ans = []
for x in nums:
if x not in seen:
seen.add(x)
left = lengths.get(x - 1, 0)
right = lengths.get(x + 1, 0)
cur = left + 1 + right
lengths[x] = cur
lengths[x - left] = cur
lengths[x + right] = cur
if cur > best:
best = cur
ans.append(best)
return ans
Time complexity: O(n) average. Space complexity: O(n).
Input: ([1, 212, 12, 12], 1212)
Expected Output: 3
Explanation: Valid ordered pairs are (0,1), (2,3), and (3,2).
Input: ([0, 0], 0)
Expected Output: 0
Explanation: No concatenation of two integer strings can have length 1.
Input: ([12, 1, 21, 121], 121)
Expected Output: 2
Explanation: The valid concatenations are 12+1 and 1+21.
Input: ([11, 11, 1], 1111)
Expected Output: 2
Explanation: The only useful split is 11|11, producing two ordered pairs from the two copies of 11.
def solution(numbers, target):
from collections import Counter
counts = Counter(str(x) for x in numbers)
t = str(target)
ans = 0
for k in range(1, len(t)):
left = t[:k]
right = t[k:]
if left not in counts or right not in counts:
continue
if left == right:
ans += counts[left] * (counts[left] - 1)
else:
ans += counts[left] * counts[right]
return ans
Time complexity: O(n + L). Space complexity: O(n).
Input: (['1'],)
Expected Output: 1
Explanation: A single digit is already a valid expression.
Input: (['1+2'],)
Expected Output: 3
Explanation: The best valid path is 1+2.
Input: (['1-2', '+3+', '4-5'],)
Expected Output: 9
Explanation: One optimal path is 1 -> + -> 3 -> + -> 5, which evaluates to 9.
Input: (['9-8', '-1+'],)
Expected Output: 9
Explanation: Starting at the digit 9 alone is better than any longer valid expression here.
def solution(grid):
if not grid:
return 0
n = len(grid)
m = len(grid[0])
NEG = -10**18
digit_dp = [[NEG] * m for _ in range(n)]
plus_dp = [[NEG] * m for _ in range(n)]
minus_dp = [[NEG] * m for _ in range(n)]
best = NEG
def best_incoming_digit(i, j):
res = NEG
if i > 0 and digit_dp[i - 1][j] > res:
res = digit_dp[i - 1][j]
if j > 0 and digit_dp[i][j - 1] > res:
res = digit_dp[i][j - 1]
return res
for i in range(n):
for j in range(m):
c = grid[i][j]
if c.isdigit():
val = ord(c) - ord('0')
cur = val
if i > 0:
if plus_dp[i - 1][j] != NEG:
cur = max(cur, plus_dp[i - 1][j] + val)
if minus_dp[i - 1][j] != NEG:
cur = max(cur, minus_dp[i - 1][j] - val)
if j > 0:
if plus_dp[i][j - 1] != NEG:
cur = max(cur, plus_dp[i][j - 1] + val)
if minus_dp[i][j - 1] != NEG:
cur = max(cur, minus_dp[i][j - 1] - val)
digit_dp[i][j] = cur
if cur > best:
best = cur
elif c == '+':
incoming = best_incoming_digit(i, j)
if incoming != NEG:
plus_dp[i][j] = incoming
else:
incoming = best_incoming_digit(i, j)
if incoming != NEG:
minus_dp[i][j] = incoming
return best if best != NEG else 0
Time complexity: O(nm). Space complexity: O(nm).
Input: ([3, 5, 5, 1],)
Expected Output: 6
Explanation: The passes add 3, then 2, then 1.
Input: ([1, 2, 3],)
Expected Output: 3
Explanation: The total is 1 + 1 + 1.
Input: ([0, 0, 0],)
Expected Output: 0
Explanation: The array is already all zeros.
Input: ([5, 1, 5],)
Expected Output: 10
Explanation: The process contributes 5, then 1, then 4.
def solution(nums):
ans = 0
stack = []
for x in nums:
while stack and stack[-1] > x:
stack.pop()
prev = stack[-1] if stack else 0
ans += x - prev
stack.append(x)
return ans
Time complexity: O(n). Space complexity: O(n).
Input: ([["This is", "a test"]], 10)
Expected Output: ["This is a", "test "]
Explanation: The first line gets extra spaces distributed from left to right.
Input: ([["ab cd", "ef"], ["gh"]], 5)
Expected Output: ["ab cd", "ef ", "gh "]
Explanation: The second block must start on a new line.
Input: ([["hello"]], 5)
Expected Output: ["hello"]
Explanation: A single word that already matches the width needs no extra padding.
Input: ([["a b c d"]], 6)
Expected Output: ["a b c", "d "]
Explanation: Three single-letter words fit on the first line, and the last word is padded.
def solution(blocks, maxWidth):
def justify(words, total_chars):
spaces = maxWidth - total_chars
if len(words) == 1:
return words[0] + ' ' * spaces
gaps = len(words) - 1
base = spaces // gaps
extra = spaces % gaps
parts = []
for i, word in enumerate(words[:-1]):
parts.append(word)
parts.append(' ' * (base + (1 if i < extra else 0)))
parts.append(words[-1])
return ''.join(parts)
result = []
for block in blocks:
words = []
for piece in block:
words.extend(piece.split())
if not words:
continue
current = []
current_chars = 0
for word in words:
if not current:
current = [word]
current_chars = len(word)
elif current_chars + len(current) + len(word) <= maxWidth:
current.append(word)
current_chars += len(word)
else:
result.append(justify(current, current_chars))
current = [word]
current_chars = len(word)
result.append(justify(current, current_chars))
return result
Time complexity: O(total characters in all words). Space complexity: O(number of words in the current line, excluding output).
Input: ('axA',)
Expected Output: 1
Explanation: The only triplet is symmetric because 'a' and 'A' match ignoring case.
Input: ('cxcbdb',)
Expected Output: 2
Explanation: The symmetric triplets are 'cxc' and 'bdb'.
Input: ('ab',)
Expected Output: 0
Explanation: A string shorter than 3 has no triplets.
Input: ('AaAa',)
Expected Output: 2
Explanation: Both triplets, 'AaA' and 'aAa', are symmetric.
def solution(s):
s = s.lower()
return sum(1 for i in range(len(s) - 2) if s[i] == s[i + 2])
Time complexity: O(n). Space complexity: O(n) due to lowercasing the string.
Input: (['A', 'A', 'P'], 3)
Expected Output: 3
Explanation: The array evolves to ['A','P','P'], then ['P','P','P'], then [].
Input: (['P', 'P', 'P', 'P'], 2)
Expected Output: 2
Explanation: Each round removes exactly two trailing P values.
Input: (['A'], 2)
Expected Output: 1
Explanation: The single A becomes P in one round, then the process stops.
Input: ([], 1)
Expected Output: 0
Explanation: Nothing can be removed or changed.
def solution(arr, rate):
n = len(arr)
a_positions = [i for i, ch in enumerate(arr) if ch == 'A']
rounds = 0
while True:
while a_positions and a_positions[-1] >= n:
a_positions.pop()
changed = False
trailing_p = n - a_positions[-1] - 1 if a_positions else n
if trailing_p >= rate:
n -= rate
changed = True
while a_positions and a_positions[-1] >= n:
a_positions.pop()
if a_positions:
a_positions.pop()
changed = True
if not changed:
break
rounds += 1
return rounds
Time complexity: O(n + number of removals). Space complexity: O(number of A values).
Input: ([1, 3, 6, 10, 15], 2)
Expected Output: 5
Explanation: The best valid pair is nums[0] and nums[2], with difference 5.
Input: ([8, 1, 4, 7], 2)
Expected Output: 1
Explanation: Indices 0 and 3 are far enough apart, and |8 - 7| = 1.
Input: ([5, 5], 1)
Expected Output: 0
Explanation: The only valid pair has equal values.
Input: ([1, 100, 2, 99, 3], 2)
Expected Output: 1
Explanation: Pairs such as (0,2) or (1,3) achieve difference 1.
def solution(nums, distance):
from collections import deque
pairs = sorted((value, idx) for idx, value in enumerate(nums))
def can(limit):
min_q = deque()
max_q = deque()
left = 0
for right, (value, idx) in enumerate(pairs):
while min_q and min_q[-1][1] >= idx:
min_q.pop()
min_q.append((right, idx))
while max_q and max_q[-1][1] <= idx:
max_q.pop()
max_q.append((right, idx))
while value - pairs[left][0] > limit:
if min_q and min_q[0][0] == left:
min_q.popleft()
if max_q and max_q[0][0] == left:
max_q.popleft()
left += 1
if right > left:
min_idx = min_q[0][1]
max_idx = max_q[0][1]
if idx - min_idx >= distance or max_idx - idx >= distance:
return True
return False
low = 0
high = max(nums) - min(nums)
while low < high:
mid = (low + high) // 2
if can(mid):
high = mid
else:
low = mid + 1
return low
Time complexity: O(n log n + n log V). Space complexity: O(n).
Input: ([1, 2, 3, 4, 5],)
Expected Output: [[1, 3, 5], [2, 4]]
Explanation: Ties alternate by group length, with B winning exact ties.
Input: ([1, 4, 2, 3],)
Expected Output: [[1], [4, 2, 3]]
Explanation: Values 2 and 3 prefer C because C has more elements greater than them.
Input: ([],)
Expected Output: [[], []]
Explanation: No elements means both groups stay empty.
Input: ([7],)
Expected Output: [[7], []]
Explanation: The first element always goes to B because everything is tied.
def solution(A):
if not A:
return [[], []]
values = sorted(set(A))
index = {v: i + 1 for i, v in enumerate(values)}
class Fenwick:
def __init__(self, n):
self.n = n
self.bit = [0] * (n + 1)
def add(self, i, delta):
while i <= self.n:
self.bit[i] += delta
i += i & -i
def query(self, i):
s = 0
while i > 0:
s += self.bit[i]
i -= i & -i
return s
bit_b = Fenwick(len(values))
bit_c = Fenwick(len(values))
B, C = [], []
for a in A:
idx = index[a]
greater_b = len(B) - bit_b.query(idx)
greater_c = len(C) - bit_c.query(idx)
if greater_b > greater_c:
B.append(a)
bit_b.add(idx, 1)
elif greater_b < greater_c:
C.append(a)
bit_c.add(idx, 1)
else:
if len(B) <= len(C):
B.append(a)
bit_b.add(idx, 1)
else:
C.append(a)
bit_c.add(idx, 1)
return [B, C]
Time complexity: O(n log n). Space complexity: O(n).