50 Array Coding Problems for Interviews — Solutions Explained
50 essential array interview problems from easy to hard — step-by-step approach, JavaScript solution, and function calls with output comments.
Introduction
Array problems dominate coding interviews — from two-pointer tricks to Kadane's algorithm and sliding windows. This post covers 50 curated problems with:
- Step-by-step approach
- Full JavaScript implementation
- Function calls with side output comments
Prerequisites: DSA Arrays fundamentals · Big O notation
Quick index
Easy (1–18)
1. Second Largest Element
Difficulty: Easy · Time: O(n) · Space: O(1)
Find the second largest element in an unsorted array. Return -1 if it does not exist.
Approach (step by step):
- Track
firstandsecondwhile scanning once. - When
xbeatsfirst, shift old first to second; otherwise update second ifxis between them. - Skip duplicates implicitly by only updating when strictly greater.
function secondLargest(arr) {
let first = -Infinity,
second = -Infinity
for (const x of arr) {
if (x > first) {
second = first
first = x
} else if (x > second && x < first) {
second = x
}
}
return second === -Infinity ? -1 : second
}Function calls with output
// ── Demo calls — output shown on the right ──
secondLargest([12, 35, 1, 10, 34, 1]) // → 34
secondLargest([10, 10, 10]) // → -1
secondLargest([5, 5, 4]) // → 42. Third Largest Element
Difficulty: Easy · Time: O(n) · Space: O(1)
Return the third distinct largest element, or -1 if fewer than three distinct values exist.
Approach (step by step):
- Maintain three variables: first, second, third.
- On each value, cascade updates when a new maximum appears.
- Return third only if it was set.
function thirdLargest(arr) {
let a = -Infinity,
b = -Infinity,
c = -Infinity
for (const x of arr) {
if (x > a) {
c = b
b = a
a = x
} else if (x > b && x < a) {
c = b
b = x
} else if (x > c && x < b) {
c = x
}
}
return c === -Infinity ? -1 : c
}Function calls with output
// ── Demo calls — output shown on the right ──
thirdLargest([1, 2, 3, 4, 5]) // → 3
thirdLargest([5, 5, 5]) // → -13. Reverse an Array
Difficulty: Easy · Time: O(n) · Space: O(1)
Reverse the array in-place using two pointers.
Approach (step by step):
- Place
leftat 0 andrightat n − 1. - Swap and move inward until pointers meet.
function reverseArray(arr) {
let l = 0,
r = arr.length - 1
while (l < r) {
;[arr[l], arr[r]] = [arr[r], arr[l]]
l++
r--
}
return arr
}Function calls with output
// ── Demo calls — output shown on the right ──
reverseArray([1, 2, 3, 4]) // → [4, 3, 2, 1]
reverseArray([10]) // → [10]4. Reverse Array in Groups
Difficulty: Easy · Time: O(n) · Space: O(1)
Reverse every subarray of size k. If the last group has fewer than k elements, reverse all remaining.
Approach (step by step):
- Step by
iin increments ofk. - Reverse the slice from
itomin(i + k - 1, n - 1).
function reverseInGroups(arr, k) {
const n = arr.length
for (let i = 0; i < n; i += k) {
let l = i,
r = Math.min(i + k - 1, n - 1)
while (l < r) {
;[arr[l], arr[r]] = [arr[r], arr[l]]
l++
r--
}
}
return arr
}Function calls with output
// ── Demo calls — output shown on the right ──
reverseInGroups([1, 2, 3, 4, 5, 6, 7, 8], 3) // → [3, 2, 1, 6, 5, 4, 8, 7]
reverseInGroups([1, 2, 3, 4, 5], 2) // → [2, 1, 4, 3, 5]5. Rotate Array
Difficulty: Easy · Time: O(n) · Space: O(1)
Rotate array to the right by k steps in-place.
Approach (step by step):
- Normalize
k %= n. - Reverse whole array, then reverse first
kand lastn-kparts.
function rotateArray(arr, k) {
const n = arr.length
if (!n) return arr
k %= n
const rev = (l, r) => {
while (l < r) {
;[arr[l], arr[r]] = [arr[r], arr[l]]
l++
r--
}
}
rev(0, n - 1)
rev(0, k - 1)
rev(k, n - 1)
return arr
}Function calls with output
// ── Demo calls — output shown on the right ──
rotateArray([1, 2, 3, 4, 5], 2) // → [4, 5, 1, 2, 3]
rotateArray([1, 2], 3) // → [2, 1]6. Three Largest Distinct Elements
Difficulty: Easy · Time: O(n) · Space: O(1)
Return the three largest distinct elements in descending order.
Approach (step by step):
- Use a Set to dedupe, sort descending, take first three.
function threeLargestDistinct(arr) {
return [...new Set(arr)].sort((a, b) => b - a).slice(0, 3)
}Function calls with output
// ── Demo calls — output shown on the right ──
threeLargestDistinct([1, 2, 4, 4, 5, 5, 3]) // → [5, 4, 3]
threeLargestDistinct([10, 10]) // → [10]7. Max Consecutive Ones
Difficulty: Easy · Time: O(n) · Space: O(1)
Find the maximum number of consecutive 1s in a binary array.
Approach (step by step):
- Track current streak and global max; reset streak on 0.
function maxConsecutiveOnes(arr) {
let cur = 0,
best = 0
for (const x of arr) {
cur = x === 1 ? cur + 1 : 0
best = Math.max(best, cur)
}
return best
}Function calls with output
// ── Demo calls — output shown on the right ──
maxConsecutiveOnes([1, 1, 0, 1, 1, 1]) // → 3
maxConsecutiveOnes([1, 0, 1, 1, 0, 1]) // → 28. Move All Zeroes To End
Difficulty: Easy · Time: O(n) · Space: O(1)
Move all zeroes to the end while maintaining relative order of non-zero elements.
Approach (step by step):
- Two-pointer: write non-zero values at
writeindex, fill rest with 0.
function moveZeroes(arr) {
let w = 0
for (const x of arr) if (x !== 0) arr[w++] = x
while (w < arr.length) arr[w++] = 0
return arr
}Function calls with output
// ── Demo calls — output shown on the right ──
moveZeroes([0, 1, 0, 3, 12]) // → [1, 3, 12, 0, 0]
moveZeroes([0, 0, 1]) // → [1, 0, 0]9. Wave Array
Difficulty: Easy · Time: O(n log n) · Space: O(1)
Arrange array so arr[0] ≥ arr[1] ≤ arr[2] ≥ arr[3]... (wave form).
Approach (step by step):
- Sort ascending, then swap pairs
(1,2), (3,4), ....
function waveArray(arr) {
arr.sort((a, b) => a - b)
for (let i = 1; i < arr.length - 1; i += 2) {
;[arr[i], arr[i + 1]] = [arr[i + 1], arr[i]]
}
return arr
}Function calls with output
// ── Demo calls — output shown on the right ──
waveArray([1, 2, 3, 4, 5, 6]) // → [1, 3, 2, 5, 4, 6]
waveArray([10, 90, 49, 2]) // → [2, 49, 10, 90]10. Plus One
Difficulty: Easy · Time: O(n) · Space: O(1)
Add 1 to a non-negative integer represented as digit array (MSB first).
Approach (step by step):
- Traverse from end, propagate carry, prepend 1 if overflow.
function plusOne(digits) {
for (let i = digits.length - 1; i >= 0; i--) {
if (digits[i] < 9) {
digits[i]++
return digits
}
digits[i] = 0
}
return [1, ...digits]
}Function calls with output
// ── Demo calls — output shown on the right ──
plusOne([1, 2, 3]) // → [1, 2, 4]
plusOne([9, 9, 9]) // → [1, 0, 0, 0]11. Stock Buy and Sell — One Transaction
Difficulty: Easy · Time: O(n) · Space: O(1)
Max profit from at most one buy and one sell.
Approach (step by step):
- Track minimum price so far; update max profit at each day.
function maxProfitOne(prices) {
let minP = Infinity,
best = 0
for (const p of prices) {
minP = Math.min(minP, p)
best = Math.max(best, p - minP)
}
return best
}Function calls with output
// ── Demo calls — output shown on the right ──
maxProfitOne([7, 1, 5, 3, 6, 4]) // → 5
maxProfitOne([7, 6, 4, 3, 1]) // → 012. Stock Buy and Sell — Multiple Transactions
Difficulty: Easy · Time: O(n) · Space: O(1)
Max profit with unlimited transactions (no overlapping holds).
Approach (step by step):
- Sum every upward day: if
prices[i] > prices[i-1], add difference.
function maxProfitMany(prices) {
let profit = 0
for (let i = 1; i < prices.length; i++) {
if (prices[i] > prices[i - 1]) profit += prices[i] - prices[i - 1]
}
return profit
}Function calls with output
// ── Demo calls — output shown on the right ──
maxProfitMany([7, 1, 5, 3, 6, 4]) // → 7
maxProfitMany([1, 2, 3, 4, 5]) // → 413. Remove Duplicates from Sorted Array
Difficulty: Easy · Time: O(n) · Space: O(1)
Remove duplicates in-place; return count of unique elements.
Approach (step by step):
- Slow pointer marks last unique; fast scans and copies new values.
function removeDuplicates(arr) {
if (!arr.length) return 0
let w = 1
for (let i = 1; i < arr.length; i++) {
if (arr[i] !== arr[w - 1]) arr[w++] = arr[i]
}
return w
}Function calls with output
// ── Demo calls — output shown on the right ──
removeDuplicates([1, 1, 2, 2, 3]) // → 3 (array starts [1,2,3])
removeDuplicates([1, 2, 3]) // → 314. Alternate Positive and Negative
Difficulty: Easy · Time: O(n) · Space: O(n)
Rearrange so positives and negatives alternate. Order among same sign may change.
Approach (step by step):
- Split into pos/neg arrays, merge alternating starting with sign of first non-zero.
function alternateSign(arr) {
const pos = arr.filter((x) => x > 0)
const neg = arr.filter((x) => x < 0)
const out = []
let i = 0,
j = 0
while (i < pos.length || j < neg.length) {
if (i < pos.length) out.push(pos[i++])
if (j < neg.length) out.push(neg[j++])
}
return out
}Function calls with output
// ── Demo calls — output shown on the right ──
alternateSign([1, -2, 3, -4, 5]) // → [1, -2, 3, -4, 5]
alternateSign([-1, -2, 3, 4]) // → [3, -1, 4, -2]15. Array Leaders
Difficulty: Easy · Time: O(n) · Space: O(1)
An element is a leader if it is greater than all elements to its right.
Approach (step by step):
- Scan right-to-left; track running max from the right.
function arrayLeaders(arr) {
const leaders = []
let maxR = -Infinity
for (let i = arr.length - 1; i >= 0; i--) {
if (arr[i] >= maxR) {
leaders.push(arr[i])
maxR = arr[i]
}
}
return leaders.reverse()
}Function calls with output
// ── Demo calls — output shown on the right ──
arrayLeaders([16, 17, 4, 3, 5, 2]) // → [17, 5, 2]
arrayLeaders([10, 4, 3, 2]) // → [10, 4, 3, 2]16. Missing and Repeating in Array
Difficulty: Easy · Time: O(n) · Space: O(1)
Array of 1..n has one missing and one repeating number. Find both.
Approach (step by step):
- Use math: sum and sum of squares, or XOR/index marking.
function missingAndRepeating(arr) {
const n = arr.length
let sum = 0,
sq = 0
for (const x of arr) {
sum += x
sq += x * x
}
const tSum = (n * (n + 1)) / 2
const tSq = (n * (n + 1) * (2 * n + 1)) / 6
const d = sum - tSum
const dSq = sq - tSq
const repeating = (dSq / d + d) / 2
const missing = repeating - d
return { missing, repeating }
}Function calls with output
// ── Demo calls — output shown on the right ──
missingAndRepeating([4, 3, 6, 2, 1, 1]) // → { missing: 5, repeating: 1 }17. Missing Ranges of Numbers
Difficulty: Easy · Time: O(n) · Space: O(1)
Given sorted unique array within [low, high], return missing ranges as strings.
Approach (step by step):
- Walk array; between consecutive values emit missing intervals.
function missingRanges(arr, low, high) {
const out = []
let prev = low - 1
const nums = [low - 1, ...arr, high + 1]
for (const cur of nums.slice(1)) {
if (cur - prev === 2) out.push(String(prev + 1))
else if (cur - prev > 2) out.push(`${prev + 1}->${cur - 1}`)
prev = cur
}
return out
}Function calls with output
// ── Demo calls — output shown on the right ──
missingRanges([0, 1, 3, 50, 75], 0, 99) // → ["2", "4->49", "51->74", "76->99"]
missingRanges([], 1, 1) // → ["1"]18. Sum of All Subarrays
Difficulty: Easy · Time: O(n) · Space: O(1)
Return sum of all subarray sums efficiently.
Approach (step by step):
- Each
arr[i]appears in(i+1) * (n-i)subarrays; multiply and sum.
function subarraySumTotal(arr) {
let total = 0
const n = arr.length
for (let i = 0; i < n; i++) total += arr[i] * (i + 1) * (n - i)
return total
}Function calls with output
// ── Demo calls — output shown on the right ──
subarraySumTotal([1, 2, 3]) // → 20
subarraySumTotal([1, 3]) // → 8Medium (19–38)
19. Next Permutation
Difficulty: Medium · Time: O(n) · Space: O(1)
Rearrange to the next lexicographically greater permutation in-place.
Approach (step by step):
- Find rightmost ascent
iwherearr[i] < arr[i+1]. - Swap
arr[i]with smallest larger element on the right. - Reverse suffix after
i.
function nextPermutation(arr) {
let i = arr.length - 2
while (i >= 0 && arr[i] >= arr[i + 1]) i--
if (i >= 0) {
let j = arr.length - 1
while (arr[j] <= arr[i]) j--
;[arr[i], arr[j]] = [arr[j], arr[i]]
}
let l = i + 1,
r = arr.length - 1
while (l < r) {
;[arr[l], arr[r]] = [arr[r], arr[l]]
l++
r--
}
return arr
}Function calls with output
// ── Demo calls — output shown on the right ──
nextPermutation([1, 2, 3]) // → [1, 3, 2]
nextPermutation([3, 2, 1]) // → [1, 2, 3]20. Majority Element
Difficulty: Medium · Time: O(n) · Space: O(1)
Find element appearing more than n/2 times (assume it always exists).
Approach (step by step):
- Boyer–Moore: cancel different pairs; survivor is majority.
function majorityElement(arr) {
let cand = arr[0],
count = 1
for (let i = 1; i < arr.length; i++) {
if (arr[i] === cand) count++
else if (--count === 0) {
cand = arr[i]
count = 1
}
}
return cand
}Function calls with output
// ── Demo calls — output shown on the right ──
majorityElement([3, 3, 4, 2, 4, 4, 2, 4, 4]) // → 4
majorityElement([2, 2, 1, 1, 1, 2, 2]) // → 221. Majority Element II
Difficulty: Medium · Time: O(n) · Space: O(1)
Find all elements appearing more than n/3 times.
Approach (step by step):
- Boyer–Moore extended with two candidates, then verify counts.
function majorityElementII(arr) {
let c1 = null,
c2 = null,
cnt1 = 0,
cnt2 = 0
for (const x of arr) {
if (x === c1) cnt1++
else if (x === c2) cnt2++
else if (cnt1 === 0) {
c1 = x
cnt1 = 1
} else if (cnt2 === 0) {
c2 = x
cnt2 = 1
} else {
cnt1--
cnt2--
}
}
const verify = (c) => (arr.filter((x) => x === c).length > arr.length / 3 ? c : null)
return [verify(c1), verify(c2)].filter((x) => x !== null)
}Function calls with output
// ── Demo calls — output shown on the right ──
majorityElementII([3, 2, 3]) // → [3]
majorityElementII([1, 1, 1, 3, 3, 2, 2, 2]) // → [1, 2]22. Minimize Heights II
Difficulty: Medium · Time: O(n log n) · Space: O(1)
Minimize max - min after adding/subtracting k to each element exactly once.
Approach (step by step):
- Sort; try making first
ielements smaller and rest larger; track min diff.
function minimizeHeights(arr, k) {
arr.sort((a, b) => a - b)
const n = arr.length
let best = arr[n - 1] - arr[0]
for (let i = 0; i < n - 1; i++) {
const low = Math.min(arr[0] + k, arr[i + 1] - k)
const high = Math.max(arr[i] + k, arr[n - 1] - k)
best = Math.min(best, high - low)
}
return best
}Function calls with output
// ── Demo calls — output shown on the right ──
minimizeHeights([1, 5, 8, 10], 2) // → 5
minimizeHeights([3, 9, 12, 16, 20], 3) // → 1123. Maximum Subarray Sum (Kadane)
Difficulty: Medium · Time: O(n) · Space: O(1)
Find contiguous subarray with largest sum.
Approach (step by step):
- Extend running sum or restart at current element; track global max.
function maxSubarraySum(arr) {
let cur = arr[0],
best = arr[0]
for (let i = 1; i < arr.length; i++) {
cur = Math.max(arr[i], cur + arr[i])
best = Math.max(best, cur)
}
return best
}Function calls with output
// ── Demo calls — output shown on the right ──
maxSubarraySum([-2, 1, -3, 4, -1, 2, 1, -5, 4]) // → 6
maxSubarraySum([5, 4, -1, 7, 8]) // → 2324. Maximum Product Subarray
Difficulty: Medium · Time: O(n) · Space: O(1)
Find contiguous subarray with largest product.
Approach (step by step):
- Track both max and min ending here (negatives flip).
function maxProductSubarray(arr) {
let best = arr[0],
maxE = arr[0],
minE = arr[0]
for (let i = 1; i < arr.length; i++) {
const x = arr[i]
const candidates = [x, maxE * x, minE * x]
maxE = Math.max(...candidates)
minE = Math.min(...candidates)
best = Math.max(best, maxE)
}
return best
}Function calls with output
// ── Demo calls — output shown on the right ──
maxProductSubarray([2, 3, -2, 4]) // → 6
maxProductSubarray([-2, 0, -1]) // → 025. Product of Array Except Self
Difficulty: Medium · Time: O(n) · Space: O(1)
Return array where output[i] is product of all elements except arr[i] without division.
Approach (step by step):
- Prefix products left-to-right, then multiply suffix running product right-to-left.
function productExceptSelf(arr) {
const n = arr.length
const out = Array(n).fill(1)
let prefix = 1
for (let i = 0; i < n; i++) {
out[i] = prefix
prefix *= arr[i]
}
let suffix = 1
for (let i = n - 1; i >= 0; i--) {
out[i] *= suffix
suffix *= arr[i]
}
return out
}Function calls with output
// ── Demo calls — output shown on the right ──
productExceptSelf([1, 2, 3, 4]) // → [24, 12, 8, 6]
productExceptSelf([2, 3, 4, 5]) // → [60, 40, 30, 24]26. Subarrays with Product Less Than K
Difficulty: Medium · Time: O(n) · Space: O(1)
Count contiguous subarrays whose product is strictly less than k.
Approach (step by step):
- Sliding window: expand right, shrink left while product ≥ k.
function subarrayProductLessK(arr, k) {
if (k <= 1) return 0
let prod = 1,
left = 0,
count = 0
for (let right = 0; right < arr.length; right++) {
prod *= arr[right]
while (prod >= k) prod /= arr[left++]
count += right - left + 1
}
return count
}Function calls with output
// ── Demo calls — output shown on the right ──
subarrayProductLessK([10, 5, 2, 6], 100) // → 8
subarrayProductLessK([1, 2, 3], 0) // → 027. Split Into Three Equal Sum Segments
Difficulty: Medium · Time: O(n) · Space: O(1)
Check if array can be split into three non-empty parts with equal sum.
Approach (step by step):
- Compute total sum; find prefix cut at sum/3 and second cut at 2*sum/3.
function canSplitThreeEqual(arr) {
const total = arr.reduce((a, b) => a + b, 0)
if (total % 3 !== 0) return false
const part = total / 3
let sum = 0,
cuts = 0
for (let i = 0; i < arr.length - 1; i++) {
sum += arr[i]
if (sum === part) {
cuts++
if (cuts === 2) return true
}
}
return false
}Function calls with output
// ── Demo calls — output shown on the right ──
canSplitThreeEqual([0, 2, 1, -6, 6, -1, 1, 0, 1]) // → true
canSplitThreeEqual([1, 1, 1]) // → false28. Max Consecutive 1s After Flipping K Zeroes
Difficulty: Medium · Time: O(n) · Space: O(1)
Longest subarray of 1s if you can flip at most k zeroes.
Approach (step by step):
- Sliding window maintains count of zeroes ≤ k.
function maxConsecutiveOnesFlip(arr, k) {
let left = 0,
zeros = 0,
best = 0
for (let right = 0; right < arr.length; right++) {
if (arr[right] === 0) zeros++
while (zeros > k) if (arr[left++] === 0) zeros--
best = Math.max(best, right - left + 1)
}
return best
}Function calls with output
// ── Demo calls — output shown on the right ──
maxConsecutiveOnesFlip([1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0], 2) // → 6
maxConsecutiveOnesFlip([0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1], 3) // → 1029. Last Moment Before Ants Fall Off Plank
Difficulty: Medium · Time: O(n) · Space: O(1)
Ants on a line move left/right at speed 1. Return time when last ant falls.
Approach (step by step):
- Max time is max of left-going distance and right-going distance.
function lastMomentAnts(n, positions, directions) {
let left = 0,
right = 0
for (let i = 0; i < positions.length; i++) {
if (directions[i] === 0) left = Math.max(left, positions[i])
else right = Math.max(right, n - positions[i])
}
return Math.max(left, right)
}Function calls with output
// ── Demo calls — output shown on the right ──
lastMomentAnts(4, [3, 2], [0, 1]) // → 2
lastMomentAnts(7, [0, 4, 7], [0, 0, 1]) // → 730. Find 0 with Farthest 1s in Binary Array
Difficulty: Medium · Time: O(n) · Space: O(1)
Flip one 0 to maximize distance to nearest 1; return index to flip.
Approach (step by step):
- Scan groups of consecutive zeroes between ones; handle edges separately.
function findBestZeroToFlip(arr) {
let best = -1,
bestLen = -1
let prevOne = -1
for (let i = 0; i <= arr.length; i++) {
if (i === arr.length || arr[i] === 1) {
const len = prevOne === -1 ? i : i - prevOne - 1
const dist = prevOne === -1 || i === arr.length ? len : Math.ceil(len / 2)
if (dist > bestLen) {
bestLen = dist
best = prevOne === -1 ? 0 : prevOne + Math.floor(len / 2) + 1
}
if (i < arr.length) prevOne = i
}
}
return best
}Function calls with output
// ── Demo calls — output shown on the right ──
findBestZeroToFlip([1, 0, 0, 0, 1]) // → 2
findBestZeroToFlip([0, 0, 0, 1]) // → 031. Merge Two Sorted Interval Lists
Difficulty: Medium · Time: O(n + m) · Space: O(1)
Merge two sorted interval arrays into one sorted non-overlapping list.
Approach (step by step):
- Standard merge by start time; combine overlapping intervals.
function mergeIntervals(a, b) {
const all = [...a, ...b].sort((x, y) => x[0] - y[0])
const out = []
for (const iv of all) {
if (!out.length || out[out.length - 1][1] < iv[0]) out.push([...iv])
else out[out.length - 1][1] = Math.max(out[out.length - 1][1], iv[1])
}
return out
}Function calls with output
// ── Demo calls — output shown on the right ──
mergeIntervals(
[
[1, 3],
[5, 7],
],
[
[2, 4],
[6, 8],
],
) // → [[1,4],[5,8]]
mergeIntervals([[1, 2]], [[3, 4]]) // → [[1,2],[3,4]]32. Rearrange Array Elements by Sign
Difficulty: Medium · Time: O(n) · Space: O(n)
Equal counts of positive and negative; alternate starting with positive.
Approach (step by step):
- Collect positives and negatives; interleave into result.
function rearrangeBySign(arr) {
const pos = [],
neg = []
for (const x of arr) (x >= 0 ? pos : neg).push(x)
const out = []
for (let i = 0; i < pos.length; i++) {
out.push(pos[i], neg[i])
}
return out
}Function calls with output
// ── Demo calls — output shown on the right ──
rearrangeBySign([3, 1, -2, -5, 2, -4]) // → [3, -2, 1, -5, 2, -4]33. Meeting Scheduler for Two Persons
Difficulty: Medium · Time: O(n log n) · Space: O(1)
Find earliest slot of duration dur where both people are free within [start, end].
Approach (step by step):
- Merge each person’s busy slots, two-pointer scan gaps.
function meetingScheduler(slotsA, slotsB, dur) {
const merge = (s) => s.sort((a, b) => a[0] - b[0])
const busy = [...merge(slotsA), ...merge(slotsB)].sort((a, b) => a[0] - b[0])
let prevEnd = busy[0]?.[0] ?? 0
for (const [s, e] of busy) {
if (s - prevEnd >= dur) return [prevEnd, prevEnd + dur]
prevEnd = Math.max(prevEnd, e)
}
return []
}Function calls with output
// ── Demo calls — output shown on the right ──
meetingScheduler(
[
[10, 50],
[60, 120],
],
[
[0, 15],
[60, 70],
],
8,
) // → [15, 23]34. Longest Mountain Subarray
Difficulty: Medium · Time: O(n) · Space: O(1)
Longest subarray that increases then decreases (length ≥ 3).
Approach (step by step):
- For each peak, expand left while ascending and right while descending.
function longestMountain(arr) {
let best = 0
for (let i = 1; i < arr.length - 1; i++) {
if (arr[i - 1] < arr[i] && arr[i] > arr[i + 1]) {
let l = i - 1,
r = i + 1
while (l > 0 && arr[l - 1] < arr[l]) l--
while (r < arr.length - 1 && arr[r + 1] < arr[r]) r++
best = Math.max(best, r - l + 1)
}
}
return best
}Function calls with output
// ── Demo calls — output shown on the right ──
longestMountain([2, 1, 4, 7, 3, 2, 5]) // → 5
longestMountain([2, 2, 2]) // → 035. Transform and Sort Array
Difficulty: Medium · Time: O(n log n) · Space: O(n)
Replace each element with sum of itself and all smaller elements, then sort.
Approach (step by step):
- Sort copy; map each value to prefix sum up to that value using binary search.
function transformSort(arr) {
const sorted = [...arr].sort((a, b) => a - b)
const prefix = sorted.reduce((acc, x) => {
acc.push((acc.at(-1) ?? 0) + x)
return acc
}, [])
const rankSum = new Map()
sorted.forEach((x, i) => {
if (!rankSum.has(x)) rankSum.set(x, prefix[i])
})
return arr.map((x) => rankSum.get(x)).sort((a, b) => a - b)
}Function calls with output
// ── Demo calls — output shown on the right ──
transformSort([2, 1, 3, 1, 2]) // → [2, 3, 4, 6, 6]36. Minimum Swaps To Group All Ones
Difficulty: Medium · Time: O(n) · Space: O(1)
Minimum swaps to bring all 1s together in a contiguous block.
Approach (step by step):
- Sliding window of size = count of ones; count zeroes in window.
function minSwapsGroupOnes(arr) {
const ones = arr.filter((x) => x === 1).length
if (!ones) return 0
let zeros = 0,
best = Infinity
for (let i = 0; i < arr.length; i++) {
if (arr[i] === 0) zeros++
if (i >= ones && arr[i - ones] === 0) zeros--
if (i >= ones - 1) best = Math.min(best, zeros)
}
return best
}Function calls with output
// ── Demo calls — output shown on the right ──
minSwapsGroupOnes([1, 0, 0, 1, 0, 1]) // → 1
minSwapsGroupOnes([0, 1, 0, 1, 1, 0, 0]) // → 137. Minimum Moves To Equalize Array
Difficulty: Medium · Time: O(n) · Space: O(1)
In one move, increment n-1 elements or decrement one. Min moves to equal array.
Approach (step by step):
- Equivalent to sum of (max - each element); answer = n*max - sum.
function minMovesEqual(arr) {
const max = Math.max(...arr)
const sum = arr.reduce((a, b) => a + b, 0)
return arr.length * max - sum
}Function calls with output
// ── Demo calls — output shown on the right ──
minMovesEqual([1, 2, 3]) // → 3
minMovesEqual([1, 1, 1]) // → 038. Minimum Indices To Equal Even-Odd Sums
Difficulty: Medium · Time: O(n) · Space: O(1)
Split at index i so sum(even indices) == sum(odd indices); return min i or -1.
Approach (step by step):
- Precompute total even/odd sums; walk i updating left/right sums.
function minIndexBalance(arr) {
let even = 0,
odd = 0
for (let i = 0; i < arr.length; i++) i % 2 === 0 ? (even += arr[i]) : (odd += arr[i])
if (even === odd) return 0
let leftE = arr[0],
leftO = 0
for (let i = 1; i < arr.length; i++) {
const rightE = even - leftE,
rightO = odd - leftO
if (leftE + (i % 2 === 0 ? 0 : arr[i]) === rightO + (i % 2 === 0 ? arr[i] : 0)) return i
if (i % 2 === 0) leftE += arr[i]
else leftO += arr[i]
}
return -1
}Function calls with output
// ── Demo calls — output shown on the right ──
minIndexBalance([2, 4, 3, 1, 5]) // → -1
minIndexBalance([1, 2, 3, 4]) // → -1Hard (39–50)
39. Trapping Rain Water
Difficulty: Hard · Time: O(n) · Space: O(1)
Compute total trapped rain water between bars.
Approach (step by step):
- Two pointers with left/right max; move shorter side inward.
function trapRainWater(arr) {
let l = 0,
r = arr.length - 1,
lMax = 0,
rMax = 0,
water = 0
while (l < r) {
if (arr[l] < arr[r]) {
lMax = Math.max(lMax, arr[l])
water += lMax - arr[l]
l++
} else {
rMax = Math.max(rMax, arr[r])
water += rMax - arr[r]
r--
}
}
return water
}Function calls with output
// ── Demo calls — output shown on the right ──
trapRainWater([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]) // → 6
trapRainWater([4, 2, 0, 3, 2, 5]) // → 940. Maximum Circular Subarray Sum
Difficulty: Hard · Time: O(n) · Space: O(1)
Max subarray sum for circular array.
Approach (step by step):
- Either normal Kadane or total - min subarray sum (wrap case).
function maxCircularSum(arr) {
const kadane = (a) => {
let cur = a[0],
best = a[0]
for (let i = 1; i < a.length; i++) {
cur = Math.max(a[i], cur + a[i])
best = Math.max(best, cur)
}
return best
}
const total = arr.reduce((a, b) => a + b, 0)
const minSub = (() => {
let cur = arr[0],
best = arr[0]
for (let i = 1; i < arr.length; i++) {
cur = Math.min(arr[i], cur + arr[i])
best = Math.min(best, cur)
}
return best
})()
if (minSub === total) return kadane(arr)
return Math.max(kadane(arr), total - minSub)
}Function calls with output
// ── Demo calls — output shown on the right ──
maxCircularSum([5, -3, 5]) // → 10
maxCircularSum([3, -1, 2, -1]) // → 441. Smallest Missing Positive Number
Difficulty: Hard · Time: O(n) · Space: O(1)
First missing positive integer in unsorted array.
Approach (step by step):
- Cyclic sort: place value v at index v-1 if 1 ≤ v ≤ n.
function firstMissingPositive(arr) {
const n = arr.length
for (let i = 0; i < n; i++) {
while (arr[i] > 0 && arr[i] <= n && arr[arr[i] - 1] !== arr[i]) {
;[arr[arr[i] - 1], arr[i]] = [arr[i], arr[arr[i] - 1]]
}
}
for (let i = 0; i < n; i++) if (arr[i] !== i + 1) return i + 1
return n + 1
}Function calls with output
// ── Demo calls — output shown on the right ──
firstMissingPositive([3, 4, -1, 1]) // → 2
firstMissingPositive([1, 2, 0]) // → 342. Jump Game
Difficulty: Hard · Time: O(n) · Space: O(1)
Can you reach the last index if arr[i] is max jump length from i?
Approach (step by step):
- Track farthest reachable; fail if
i > farthest.
function canJump(arr) {
let far = 0
for (let i = 0; i < arr.length; i++) {
if (i > far) return false
far = Math.max(far, i + arr[i])
if (far >= arr.length - 1) return true
}
return true
}Function calls with output
// ── Demo calls — output shown on the right ──
canJump([2, 3, 1, 1, 4]) // → true
canJump([3, 2, 1, 0, 4]) // → false43. Closest Subsequence Sum
Difficulty: Hard · Time: O(n · 2^(n/2)) · Space: O(2^(n/2))
Pick subsequence closest to target; return that sum.
Approach (step by step):
- Meet-in-the-middle: enumerate left/right sums, binary search best pair.
function closestSubseqSum(arr, target) {
const sums = (nums) => {
const out = [0]
for (const x of nums) {
const len = out.length
for (let i = 0; i < len; i++) out.push(out[i] + x)
}
return out.sort((a, b) => a - b)
}
const mid = Math.floor(arr.length / 2)
const left = sums(arr.slice(0, mid))
const right = sums(arr.slice(mid))
let best = Infinity,
ans = 0
for (const a of left) {
let lo = 0,
hi = right.length - 1
while (lo <= hi) {
const s = a + right[lo]
if (Math.abs(s - target) < Math.abs(best - target)) {
best = s
ans = s
}
if (s < target) lo++
else hi--
}
}
return ans
}Function calls with output
// ── Demo calls — output shown on the right ──
closestSubseqSum([-1, 2, 1], 4) // → 3
closestSubseqSum([2, -1, 0, 1, -3, 3, -3], 2) // → 244. Smallest Non-Representable Sum
Difficulty: Hard · Time: O(n log n) · Space: O(1)
Smallest positive integer that cannot be formed as sum of subset of array.
Approach (step by step):
- Sort positives; extend reachable range
[1, res)if next coin ≤ res.
function smallestNonRepresentable(arr) {
const pos = arr.filter((x) => x > 0).sort((a, b) => a - b)
let res = 1
for (const x of pos) {
if (x > res) break
res += x
}
return res
}Function calls with output
// ── Demo calls — output shown on the right ──
smallestNonRepresentable([1, 1, 1, 1]) // → 5
smallestNonRepresentable([1, 2, 5, 10]) // → 445. Smallest Range Covering K Lists
Difficulty: Hard · Time: O(n log k) · Space: O(k)
Each list is sorted; find smallest range including at least one from each list.
Approach (step by step):
- Min-heap on list heads; track window min/max.
function smallestRange(lists) {
const heap = lists.map((list, i) => ({ val: list[0], i, j: 0 }))
heap.sort((a, b) => a.val - b.val)
let curMax = Math.max(...heap.map((x) => x.val))
let best = [-1e9, 1e9]
while (true) {
const min = heap[0]
if (curMax - min.val < best[1] - best[0]) best = [min.val, curMax]
if (min.j + 1 >= lists[min.i].length) break
min.j++
min.val = lists[min.i][min.j]
curMax = Math.max(curMax, min.val)
heap.sort((a, b) => a.val - b.val)
}
return best
}Function calls with output
// ── Demo calls — output shown on the right ──
smallestRange([
[4, 10, 15, 24, 26],
[0, 9, 12, 20],
[5, 18, 22, 30],
]) // → [20, 24]46. Count Subarrays with K Distinct
Difficulty: Hard · Time: O(n) · Space: O(k)
Count subarrays with exactly k distinct integers.
Approach (step by step):
- Use atMost(k) - atMost(k-1) with sliding window frequency map.
function subarraysWithKDistinct(arr, k) {
const atMost = (goal) => {
const freq = new Map()
let left = 0,
count = 0
for (let right = 0; right < arr.length; right++) {
freq.set(arr[right], (freq.get(arr[right]) ?? 0) + 1)
while (freq.size > goal) {
const l = arr[left++]
const f = freq.get(l) - 1
if (f === 0) freq.delete(l)
else freq.set(l, f)
}
count += right - left + 1
}
return count
}
return atMost(k) - atMost(k - 1)
}Function calls with output
// ── Demo calls — output shown on the right ──
subarraysWithKDistinct([1, 2, 1, 2, 3], 2) // → 7
subarraysWithKDistinct([1, 2, 1, 3, 4], 3) // → 347. Next Smallest Palindrome
Difficulty: Hard · Time: O(n) · Space: O(1)
Given palindrome digit array, return next smallest palindrome as digit array.
Approach (step by step):
- Mirror first half to second; increment middle like next permutation on left half.
function nextPalindrome(digits) {
const n = digits.length
const half = Math.floor(n / 2)
const left = digits.slice(0, half)
let carry = 1
for (let i = half - 1; i >= 0 && carry; i--) {
const sum = left[i] + carry
left[i] = sum % 10
carry = Math.floor(sum / 10)
}
if (carry)
return Array(n + 1)
.fill(0)
.map((_, i) => (i === 0 || i === n ? 1 : 0))
const out = [...left]
if (n % 2) out.push(digits[half])
return [...out, ...left.slice().reverse()]
}Function calls with output
// ── Demo calls — output shown on the right ──
nextPalindrome([1, 2, 2, 1]) // → [2, 1, 1, 2]
nextPalindrome([9, 9, 9]) // → [1, 0, 0, 0, 1]48. Maximum Sum Among All Rotations
Difficulty: Hard · Time: O(n) · Space: O(1)
Max sum of i*arr[i] over all circular rotations.
Approach (step by step):
- Derive rotation delta: add (sum - n*last) each step; track max.
function maxSumRotations(arr) {
const n = arr.length
let sum = 0,
cur = 0
for (let i = 0; i < n; i++) {
sum += arr[i]
cur += i * arr[i]
}
let best = cur
for (let i = 1; i < n; i++) {
cur += sum - n * arr[n - i]
best = Math.max(best, cur)
}
return best
}Function calls with output
// ── Demo calls — output shown on the right ──
maxSumRotations([8, 3, 1, 2]) // → 29
maxSumRotations([1, 2, 3]) // → 849. Two Sum
Difficulty: Easy · Time: O(n) · Space: O(n)
Return indices of two numbers that add up to target.
Approach (step by step):
- Hash map stores value → index; for each x check if target-x seen.
function twoSum(arr, target) {
const map = new Map()
for (let i = 0; i < arr.length; i++) {
const need = target - arr[i]
if (map.has(need)) return [map.get(need), i]
map.set(arr[i], i)
}
return []
}Function calls with output
// ── Demo calls — output shown on the right ──
twoSum([2, 7, 11, 15], 9) // → [0, 1]
twoSum([3, 2, 4], 6) // → [1, 2]50. Container With Most Water
Difficulty: Medium · Time: O(n) · Space: O(1)
Max area formed by two lines (heights array) with x-axis.
Approach (step by step):
- Two pointers at ends; move shorter side inward.
function maxArea(arr) {
let l = 0,
r = arr.length - 1,
best = 0
while (l < r) {
best = Math.max(best, Math.min(arr[l], arr[r]) * (r - l))
if (arr[l] < arr[r]) l++
else r--
}
return best
}Function calls with output
// ── Demo calls — output shown on the right ──
maxArea([1, 8, 6, 2, 5, 4, 8, 3, 7]) // → 49
maxArea([1, 1]) // → 1Summary
| Level | Count | Patterns |
|---|---|---|
| Easy | 18 | Two pointers, prefix, single scan |
| Medium | 20 | Sliding window, Kadane, Boyer–Moore |
| Hard | 12 | Meet-in-the-middle, cyclic sort, multi-list heap |
Next reads: DSA Arrays · Binary Search · Merge Sort
Subscribe to my newsletter
Stay up to date and get notified when I share new contents.
No spam ever, unsubscribe anytime