Skip to content
wins.solutions

Top Array Interview Questions (with Answers)

30 array questions that come up again and again in placement coding rounds, grouped into five patterns: two pointers, sliding window, prefix sums, hashing, and intervals and sorting. Each has a LeetCode link, the approach, a Python sketch and its complexity.

FreePractice sheet19 min readAll levelsBy wins.solutions teamUpdated

Arrays are the first data structure most interviewers reach for. Every language has them, a problem can be stated in two lines, and an online judge can check a solution against hidden test cases automatically. That makes them a natural fit for online assessments and first technical rounds. They also sit underneath much of what comes later: strings are arrays of characters, matrices are arrays of arrays, and most dynamic programming tables are arrays filled in a careful order.

The useful part is that array questions repeat. A handful of ideas solve most of them: moving two indices, keeping a running window, precomputing sums, trading memory for fast lookups, and sorting first. Learning to spot which idea a problem needs is worth more than memorising any single solution, so this sheet is organised by pattern rather than by difficulty.

How to use it:

  1. Read the pattern first, especially the part about how to recognise it.
  2. Attempt each problem on LeetCode using the Practice link before you open the answer. Give it a fixed amount of time, not unlimited.
  3. Check the answer for the approach, a short Python sketch and the time and space complexity. The approaches carry over directly to C++ or Java.
  4. Tick a question only when you can solve it without looking. Your progress is saved in this browser.
  1. Read the pattern
  2. Attempt the problem
  3. Check the answer
  4. Re-solve later
The loop for every question on this sheet

Two pointers

Two pointers means keeping two indices into the array and moving them by a rule, so that one pass does the work of a nested loop. The indices either start at opposite ends and walk towards each other, or both start on the left, one reading and one writing. Recognise it when the array is sorted (or can be sorted without losing what the question asks for), when you need a pair or triplet that meets a target, when the answer depends on the two ends of a range, or when you must rearrange elements in place with O(1) extra space. Every correct two-pointer solution rests on one argument: each move discards only positions that cannot be part of the answer.

Two pointers

0 / 6 done
  1. Show answer

    Keep a write pointer w marking where the next non-zero value belongs. Scan with a read pointer; whenever you find a non-zero value, swap it into position w and advance w. Non-zero values keep their relative order, and the zeros end up at the back in a single pass.

    def move_zeroes(nums):
        w = 0
        for r in range(len(nums)):
            if nums[r] != 0:
                nums[w], nums[r] = nums[r], nums[w]
                w += 1

    Time: O(n). Space: O(1).

  2. Two Sum II - Input Array Is SortedMediumPractice (opens in a new tab)
    Show answer

    Start l at the first element and r at the last. If the pair sums to less than the target, the only way to increase it is to move l right; if it is too large, move r left. Because the array is sorted, each move discards an element that cannot pair with anything still in range. The problem expects 1-based indices.

    def two_sum_sorted(numbers, target):
        l, r = 0, len(numbers) - 1
        while l < r:
            s = numbers[l] + numbers[r]
            if s == target:
                return [l + 1, r + 1]  # 1-based indices
            if s < target:
                l += 1
            else:
                r -= 1
        return []

    Time: O(n). Space: O(1).

  3. Show answer

    This is the Dutch national flag problem. Keep three pointers: everything before low is 0, everything after high is 2, and mid scans the unknown middle. A 0 is swapped to low, a 2 is swapped to high, and a 1 stays. After swapping with high, do not advance mid, because the value that just arrived has not been examined yet.

    def sort_colors(nums):
        low, mid, high = 0, 0, len(nums) - 1
        while mid <= high:
            if nums[mid] == 0:
                nums[low], nums[mid] = nums[mid], nums[low]
                low += 1
                mid += 1
            elif nums[mid] == 1:
                mid += 1
            else:
                nums[mid], nums[high] = nums[high], nums[mid]
                high -= 1

    Time: O(n), one pass. Space: O(1).

  4. Show answer

    Sort the array. Fix each element nums[i] in turn and run the Two Sum II technique on the rest of the array, looking for a pair that sums to -nums[i]. Skip repeated values of nums[i], and after recording a triplet skip repeated values of nums[l], so no triplet is reported twice. Once nums[i] is positive, no later triplet can sum to zero.

    def three_sum(nums):
        nums.sort()
        res = []
        for i in range(len(nums) - 2):
            if nums[i] > 0:
                break
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            l, r = i + 1, len(nums) - 1
            while l < r:
                s = nums[i] + nums[l] + nums[r]
                if s < 0:
                    l += 1
                elif s > 0:
                    r -= 1
                else:
                    res.append([nums[i], nums[l], nums[r]])
                    l += 1
                    r -= 1
                    while l < r and nums[l] == nums[l - 1]:
                        l += 1
        return res

    Time: O(n²): the sort is O(n log n) and each of the n fixed elements runs a linear scan. Space: O(1) extra apart from the output and the memory the sort uses.

  5. Container With Most WaterMediumPractice (opens in a new tab)
    Show answer

    Start with the widest container, l = 0 and r = n - 1. Its area is min(height[l], height[r]) * (r - l). Then move the shorter line inwards. Moving the taller line can never help: the width shrinks, and the height is still capped by the shorter line, so every container using the shorter line has already been beaten.

    def max_area(height):
        l, r = 0, len(height) - 1
        best = 0
        while l < r:
            best = max(best, min(height[l], height[r]) * (r - l))
            if height[l] < height[r]:
                l += 1
            else:
                r -= 1
        return best

    Time: O(n). Space: O(1).

  6. Trapping Rain WaterHardPractice (opens in a new tab)
    Show answer

    The water above bar i is min(highest bar on its left, highest bar on its right) - height[i]. Walk two pointers inwards while tracking left_max and right_max. Whenever height[l] < height[r], the right side always has a wall at least as tall as left_max, so the water at l depends only on left_max: add it and move l. Otherwise do the same from the right.

    def trap(height):
        l, r = 0, len(height) - 1
        left_max = right_max = 0
        water = 0
        while l < r:
            if height[l] < height[r]:
                left_max = max(left_max, height[l])
                water += left_max - height[l]
                l += 1
            else:
                right_max = max(right_max, height[r])
                water += right_max - height[r]
                r -= 1
        return water

    Time: O(n). Space: O(1). A prefix-maximum and suffix-maximum array version is easier to explain first and uses O(n) space.

Sliding window

A sliding window is a contiguous range nums[l..r] that moves across the array while you maintain a running summary of it: a sum, a count or a frequency map. Instead of recomputing every subarray from scratch, you add the element entering on the right and remove the one leaving on the left. Fixed-size windows move both ends together. Variable-size windows grow r on every step and shrink l while the window breaks a condition. Recognise it when the question asks for the longest, shortest or best contiguous subarray, or asks you to count subarrays, under a condition that behaves predictably as the window grows. With non-negative numbers, for example, adding an element never decreases the sum, so once a window is too large, every larger window starting at the same l is too.

Sliding window

0 / 6 done
  1. Maximum Average Subarray IEasyPractice (opens in a new tab)
    Show answer

    A fixed window of size k. Sum the first k elements, then slide one step at a time: add the element entering on the right and subtract the one leaving on the left. Track the best sum and divide by k once at the end.

    def find_max_average(nums, k):
        window = sum(nums[i] for i in range(k))
        best = window
        for i in range(k, len(nums)):
            window += nums[i] - nums[i - k]
            best = max(best, window)
        return best / k

    Time: O(n). Space: O(1).

  2. Best Time to Buy and Sell StockEasyPractice (opens in a new tab)
    Show answer

    For each day, the best trade that sells today buys at the lowest price seen so far. Keep that running minimum and the best profit. You can see it as a window whose left edge jumps forward to every new minimum price.

    def max_profit(prices):
        min_price = float("inf")
        best = 0
        for p in prices:
            min_price = min(min_price, p)
            best = max(best, p - min_price)
        return best

    Time: O(n). Space: O(1).

  3. Minimum Size Subarray SumMediumPractice (opens in a new tab)
    Show answer

    All numbers are positive, so a window's sum only grows as it widens. Extend r and add to the running total. While the total is at least the target, record the window length and shrink from the left, since a shorter window starting later might still qualify.

    def min_sub_array_len(target, nums):
        l = 0
        total = 0
        best = float("inf")
        for r, x in enumerate(nums):
            total += x
            while total >= target:
                best = min(best, r - l + 1)
                total -= nums[l]
                l += 1
        return 0 if best == float("inf") else best

    Time: O(n). Each element enters and leaves the window at most once, so the inner loop is O(n) across the whole run, not per step. Space: O(1).

  4. Max Consecutive Ones IIIMediumPractice (opens in a new tab)
    Show answer

    Rephrase the question: find the longest window containing at most k zeros, because those are the zeros you would flip. Count zeros as the window grows, and shrink from the left whenever the count goes above k.

    def longest_ones(nums, k):
        l = 0
        zeros = 0
        best = 0
        for r, x in enumerate(nums):
            if x == 0:
                zeros += 1
            while zeros > k:
                if nums[l] == 0:
                    zeros -= 1
                l += 1
            best = max(best, r - l + 1)
        return best

    Time: O(n). Space: O(1).

  5. Subarray Product Less Than KMediumPractice (opens in a new tab)
    Show answer

    The numbers are positive, so the product grows as the window widens. For each r, multiply in nums[r] and shrink from the left until the product is below k. Every subarray that ends at r and starts anywhere in l..r is then valid, which adds r - l + 1 to the count. If k is 1 or less, no product of positive integers can be below it.

    def num_subarray_product_less_than_k(nums, k):
        if k <= 1:
            return 0
        prod = 1
        l = 0
        count = 0
        for r, x in enumerate(nums):
            prod *= x
            while prod >= k:
                prod //= nums[l]
                l += 1
            count += r - l + 1
        return count

    Time: O(n). Space: O(1).

  6. Sliding Window MaximumHardPractice (opens in a new tab)
    Show answer

    Keep a deque of indices whose values are in decreasing order. Before adding index i, pop every index from the back whose value is not larger than nums[i]; those values can never be a window maximum again. Drop the front index once it falls out of the window. The front of the deque is always the current window's maximum.

    from collections import deque
     
    def max_sliding_window(nums, k):
        dq = deque()  # indices; their values decrease from front to back
        res = []
        for i, x in enumerate(nums):
            while dq and nums[dq[-1]] <= x:
                dq.pop()
            dq.append(i)
            if dq[0] <= i - k:
                dq.popleft()
            if i >= k - 1:
                res.append(nums[dq[0]])
        return res

    Time: O(n), because each index is pushed and popped at most once. Space: O(k) for the deque.

Every variable-size window above depends on that predictable behaviour: either all the numbers are positive, or the condition is a count that only rises as the window grows. When the array can contain negative numbers, shrinking the window no longer reliably fixes a sum that is too large, and the sliding window quietly gives wrong answers. That is the gap prefix sums fill.

Prefix sums

A prefix sum array stores running totals: prefix[i] is the sum of the first i elements, so the sum of any range nums[l..r] is prefix[r + 1] - prefix[l], a single subtraction. Recognise it when you must answer many range-sum queries on an array that does not change, when the question asks about subarrays whose sum equals or is divisible by some value (especially when negative numbers rule out a sliding window), or when you need a balance point between a left part and a right part. The same idea works for running products, counts and XOR. The most common upgrade stores prefix sums in a hash map as you go, so "was there an earlier point where the running total was prefix - k?" becomes one lookup.

Prefix sums

0 / 6 done
  1. Range Sum Query - ImmutableEasyPractice (opens in a new tab)
    Show answer

    Build the prefix array once in the constructor, with a leading 0 so that ranges starting at index 0 need no special case. Each query is then one subtraction.

    class NumArray:
        def __init__(self, nums):
            self.prefix = [0]
            for x in nums:
                self.prefix.append(self.prefix[-1] + x)
     
        def sumRange(self, left, right):
            return self.prefix[right + 1] - self.prefix[left]

    Time: O(n) to build, O(1) per query. Space: O(n).

  2. Find Pivot IndexEasyPractice (opens in a new tab)
    Show answer

    Compute the total once. Walk left to right keeping the sum of everything before the current index; the sum to the right is then total - left - nums[i]. Return the first index where the two sides match, or -1.

    def pivot_index(nums):
        total = sum(nums)
        left = 0
        for i, x in enumerate(nums):
            if left == total - left - x:
                return i
            left += x
        return -1

    Time: O(n). Space: O(1).

  3. Maximum SubarrayMediumPractice (opens in a new tab)
    Show answer

    The sum of a subarray ending at j is prefix[j + 1] minus some earlier prefix, so the best one subtracts the smallest earlier prefix. Kadane's algorithm is the same idea in running form: cur is the best sum of a subarray ending at the current index, and you restart from the current element whenever carrying the previous sum would only drag it down. Start from nums[0], not 0, so an all-negative array returns its largest element.

    def max_sub_array(nums):
        best = cur = nums[0]
        for i in range(1, len(nums)):
            cur = max(nums[i], cur + nums[i])
            best = max(best, cur)
        return best

    Time: O(n). Space: O(1).

  4. Product of Array Except SelfMediumPractice (opens in a new tab)
    Show answer

    The answer at i is the product of everything before i times the product of everything after it. Fill the output with prefix products in a left-to-right pass, then multiply in suffix products in a right-to-left pass. No division is needed, which also avoids the special cases that zeros would cause.

    def product_except_self(nums):
        n = len(nums)
        ans = [1] * n
        prefix = 1
        for i in range(n):
            ans[i] = prefix
            prefix *= nums[i]
        suffix = 1
        for i in range(n - 1, -1, -1):
            ans[i] *= suffix
            suffix *= nums[i]
        return ans

    Time: O(n). Space: O(1) extra, since the problem does not count the output array.

  5. Subarray Sum Equals KMediumPractice (opens in a new tab)
    Show answer

    Negative numbers are allowed, so a sliding window will not work. Keep a running prefix sum and a hash map counting how often each prefix sum has occurred. A subarray ending here sums to k exactly when an earlier prefix equals prefix - k, so add that count. Seed the map with a prefix sum of 0 seen once, for subarrays that start at index 0.

    def subarray_sum(nums, k):
        seen = {0: 1}  # prefix sum -> number of times seen
        prefix = 0
        count = 0
        for x in nums:
            prefix += x
            count += seen.get(prefix - k, 0)
            seen[prefix] = seen.get(prefix, 0) + 1
        return count

    Time: O(n) on average, because of the hash map. Space: O(n).

  6. Contiguous ArrayMediumPractice (opens in a new tab)
    Show answer

    Treat every 0 as -1. A subarray with equal numbers of 0s and 1s now has a sum of 0, which means the running sum at its end equals the running sum just before its start. Store the first index where each running sum appears; the longest answer ending at i is i minus that first index. Seed the map with sum 0 at index -1.

    def find_max_length(nums):
        first = {0: -1}  # running sum -> earliest index
        prefix = 0
        best = 0
        for i, x in enumerate(nums):
            prefix += 1 if x == 1 else -1
            if prefix in first:
                best = max(best, i - first[prefix])
            else:
                first[prefix] = i
        return best

    Time: O(n). Space: O(n).

Hashing

A hash set or hash map gives average O(1) insertion and lookup, which turns "search the rest of the array for something" from an O(n) scan into a single step. Recognise it when your brute force has an inner loop hunting for a complement, a duplicate or a count, when you need frequencies, or when membership matters more than order. The cost is O(n) extra memory, and the O(1) is an average: heavy collisions can make individual operations slower, which is worth knowing if the interviewer asks about worst cases. If you are asked for O(1) extra space, look for a sort-plus-two-pointers solution, or for a way to use the array itself as the hash table, as in First Missing Positive below.

Hashing

0 / 6 done
  1. Show answer

    Store each value's index in a hash map as you scan. For each element x, check whether target - x is already in the map before inserting x; checking first stops an element from pairing with itself.

    def two_sum(nums, target):
        index_of = {}
        for i, x in enumerate(nums):
            if target - x in index_of:
                return [index_of[target - x], i]
            index_of[x] = i
        return []

    Time: O(n). Space: O(n). Sorting plus two pointers also finds the pair but loses the original indices unless you sort (value, index) pairs.

  2. Contains DuplicateEasyPractice (opens in a new tab)
    Show answer

    Add each value to a set and return as soon as you meet one that is already there. If memory is tight, sorting and comparing neighbours works too, at O(n log n) time.

    def contains_duplicate(nums):
        seen = set()
        for x in nums:
            if x in seen:
                return True
            seen.add(x)
        return False

    Time: O(n). Space: O(n).

  3. Majority ElementEasyPractice (opens in a new tab)
    Show answer

    Counting with a hash map and returning the most frequent value is the direct answer. The usual follow-up asks for O(1) space: Boyer-Moore voting keeps one candidate and a counter, adding 1 for a match and subtracting 1 otherwise, and takes a new candidate whenever the counter reaches 0. Because the majority value appears more than n/2 times, it survives all the cancelling.

    from collections import Counter
     
    def majority_element(nums):
        counts = Counter(nums)
        return max(counts, key=counts.get)
     
    def majority_element_voting(nums):  # Boyer-Moore, O(1) space
        candidate, count = None, 0
        for x in nums:
            if count == 0:
                candidate = x
            count += 1 if x == candidate else -1
        return candidate

    Time: O(n) for both. Space: O(n) with the counter, O(1) with voting.

  4. Top K Frequent ElementsMediumPractice (opens in a new tab)
    Show answer

    Count frequencies with a hash map. No value can occur more than n times, so place each value in a bucket indexed by its frequency, then walk the buckets from highest to lowest until you have k values. A min-heap of size k is the other common answer, at O(n log k).

    from collections import Counter
     
    def top_k_frequent(nums, k):
        counts = Counter(nums)
        buckets = [[] for _ in range(len(nums) + 1)]  # buckets[f]: values seen f times
        for value, freq in counts.items():
            buckets[freq].append(value)
        res = []
        for freq in range(len(nums), 0, -1):
            for value in buckets[freq]:
                res.append(value)
                if len(res) == k:
                    return res
        return res

    Time: O(n). Space: O(n).

  5. Longest Consecutive SequenceMediumPractice (opens in a new tab)
    Show answer

    Put every value in a set. A value x starts a run only if x - 1 is not in the set; from each such start, count upwards while x + 1, x + 2 and so on are present. Every value is visited at most twice overall. Loop over the set rather than the original array, so duplicate starting values do not repeat the same run.

    def longest_consecutive(nums):
        values = set(nums)
        best = 0
        for x in values:
            if x - 1 not in values:  # x starts a run
                length = 1
                while x + length in values:
                    length += 1
                best = max(best, length)
        return best

    Time: O(n) on average. Space: O(n). Sorting first gives a simpler O(n log n) solution, which is a fine starting point to mention.

  6. First Missing PositiveHardPractice (opens in a new tab)
    Show answer

    The answer is always between 1 and n + 1, so only values in 1..n matter. Use the array as its own hash table: swap each such value v into index v - 1 until every position holds its own value or a value that does not belong anywhere. The first index i where nums[i] != i + 1 gives the answer i + 1; if every position matches, the answer is n + 1.

    def first_missing_positive(nums):
        n = len(nums)
        for i in range(n):
            while 1 <= nums[i] <= n and nums[nums[i] - 1] != nums[i]:
                j = nums[i] - 1
                nums[i], nums[j] = nums[j], nums[i]
        for i in range(n):
            if nums[i] != i + 1:
                return i + 1
        return n + 1

    Time: O(n). The while loop looks nested, but every swap puts one value in its final place, so there are at most n swaps in total. Space: O(1). Compute j before swapping; in Python, writing the swap with nums[nums[i] - 1] on both sides reads nums[i] after it has already changed.

Intervals and sorting

Sorting costs O(n log n) and often makes the rest of the problem linear: duplicates become neighbours, pairs can be found with two pointers, and overlapping ranges end up next to each other. Interval questions, such as meetings, bookings or time ranges given as [start, end] pairs, almost always begin with a sort. Sort by start when you need to merge overlapping intervals, and by end when you are greedily keeping as many non-overlapping intervals as possible. Then make one pass, comparing each interval with the last one you kept. Recognise the pattern when the input is a list of ranges, when the brute force compares every pair, or when the input order does not affect the answer. The sort usually dominates the final complexity, so say that when you state it.

Intervals and sorting

0 / 6 done
  1. Merge Sorted ArrayEasyPractice (opens in a new tab)
    Show answer

    nums1 has room for both arrays at its end. Fill it from the back: compare the largest remaining elements of each array and write the larger one into the last free slot. Filling from the back never overwrites a nums1 value you still need. When nums2 runs out, the rest of nums1 is already in place.

    def merge(nums1, m, nums2, n):
        i, j, w = m - 1, n - 1, m + n - 1
        while j >= 0:
            if i >= 0 and nums1[i] > nums2[j]:
                nums1[w] = nums1[i]
                i -= 1
            else:
                nums1[w] = nums2[j]
                j -= 1
            w -= 1

    Time: O(m + n). Space: O(1).

  2. Merge IntervalsMediumPractice (opens in a new tab)
    Show answer

    Sort by start. Walk through the intervals: if the current one starts at or before the end of the last merged interval, they overlap, so extend that end to the larger of the two; otherwise, start a new merged interval.

    def merge_intervals(intervals):
        intervals.sort(key=lambda iv: iv[0])
        merged = []
        for start, end in intervals:
            if merged and start <= merged[-1][1]:
                merged[-1][1] = max(merged[-1][1], end)
            else:
                merged.append([start, end])
        return merged

    Time: O(n log n) for the sort; the merge pass is O(n). Space: O(n) for the output.

  3. Insert IntervalMediumPractice (opens in a new tab)
    Show answer

    The input is already sorted and non-overlapping, so no sort is needed. Work in three phases: copy every interval that ends before the new one starts, merge every interval that starts before the new one ends into it, then copy the rest.

    def insert(intervals, new_interval):
        res = []
        i, n = 0, len(intervals)
        start, end = new_interval
        while i < n and intervals[i][1] < start:
            res.append(intervals[i])
            i += 1
        while i < n and intervals[i][0] <= end:
            start = min(start, intervals[i][0])
            end = max(end, intervals[i][1])
            i += 1
        res.append([start, end])
        res.extend(intervals[i:])
        return res

    Time: O(n). Space: O(n) for the output.

  4. Non-overlapping IntervalsMediumPractice (opens in a new tab)
    Show answer

    Minimising removals is the same as keeping as many non-overlapping intervals as possible. Sort by end time and greedily keep each interval that starts at or after the end of the last one kept: the interval that finishes earliest leaves the most room for the rest. In this problem, intervals that only touch, such as [1, 2] and [2, 3], do not overlap.

    def erase_overlap_intervals(intervals):
        intervals.sort(key=lambda iv: iv[1])
        kept = 0
        last_end = float("-inf")
        for start, end in intervals:
            if start >= last_end:
                kept += 1
                last_end = end
        return len(intervals) - kept

    Time: O(n log n). Space: O(1) extra apart from the sort.

  5. Interval List IntersectionsMediumPractice (opens in a new tab)
    Show answer

    Both lists are sorted and disjoint, so walk them with one pointer each. Two intervals intersect in [max(starts), min(ends)] whenever that range is not empty. Then advance whichever interval ends first, because it cannot intersect anything later in the other list.

    def interval_intersection(first, second):
        i = j = 0
        res = []
        while i < len(first) and j < len(second):
            lo = max(first[i][0], second[j][0])
            hi = min(first[i][1], second[j][1])
            if lo <= hi:
                res.append([lo, hi])
            if first[i][1] < second[j][1]:
                i += 1
            else:
                j += 1
        return res

    Time: O(m + n). Space: O(1) extra apart from the output.

  6. Kth Largest Element in an ArrayMediumPractice (opens in a new tab)
    Show answer

    Sorting and taking nums[n - k] works in O(n log n), and is worth saying first. The expected improvement keeps a min-heap of the k largest values seen so far: push each value, and pop the smallest whenever the heap grows past k. The top of the heap is the answer. Quickselect with a random pivot is the usual follow-up, at O(n) on average and O(n²) in the worst case.

    import heapq
     
    def find_kth_largest(nums, k):
        heap = []
        for x in nums:
            heapq.heappush(heap, x)
            if len(heap) > k:
                heapq.heappop(heap)
        return heap[0]

    Time: O(n log k). Space: O(k).

Real interview problems often combine these patterns. 3Sum is sorting plus two pointers, Subarray Sum Equals K is prefix sums plus hashing, and Sliding Window Maximum adds a deque to a window. When a new problem does not fit one pattern cleanly, ask which two it might combine.

How to practise this sheet

Solving 30 problems once is not the goal. The goal is solving a problem you have never seen, from one of these patterns, under time pressure. Three habits make the difference.

Spaced repetition

Re-solve each problem from a blank editor after a gap; re-reading the answer does not count. A simple schedule is to attempt a problem today, again a few days later, and again a week or two after that. If you get stuck on a revisit, shorten the gap for that problem. Keep a one-line note for each problem with its pattern and key insight, for example "shrink while the window holds more than k zeros". Those notes become your revision sheet before interviews.

Time yourself

Set a timer before you start. A reasonable starting target is about 15 to 20 minutes for an easy problem and 30 to 40 for a medium, including reading the problem and testing your code. If you have made no progress after about 20 minutes, read only the approach paragraph of the answer, close it, and write the code yourself. Online assessments are timed, so practise under the same kind of pressure.

Explain aloud

Interviewers assess your reasoning, not only your final code. Practise saying your solution out loud in this order:

  1. Restate the problem and ask about edge cases: empty input, a single element, duplicates, negative numbers, very large values.
  2. Describe the brute force and its complexity.
  3. Name the pattern that improves it and explain why the improvement is correct.
  4. Write the code, narrating the important decisions.
  5. Dry-run it on a small example, then state the time and space complexity.

Recording yourself once or twice is uncomfortable, and it shows you quickly where your explanation gets vague.

Arrays are one part of a wider plan. The 90-day placement preparation roadmap shows where this sheet fits alongside the other DSA topics, CS fundamentals, aptitude and mock interviews.

  • Free

    90-Day Placement Preparation Roadmap

    A 90-day plan for campus placements in seven stages: DSA foundations, core patterns, CS fundamentals, aptitude, projects and resume, mock interviews and final revision. Each stage says what to do and how to tell when you are ready to move on.

    RoadmapWebAll levels

    FreeView roadmap
  • Free

    Quantitative Aptitude Formula Sheet (Free PDF)

    Every formula from our quantitative aptitude guide on a printable PDF: percentages, interest, ratios, time and work, speed and distance, permutations and probability.

    Free PDFPDFBeginner

    FreeDownload
  • Free

    20 HR Interview Questions for Freshers (with Sample Answers)

    The HR questions freshers commonly face in campus and off-campus interviews, grouped by theme. For each one: what the interviewer is checking, a simple structure for your answer, and a short sample answer to adapt to your own experience.

    GuideWebBeginner

    FreeRead
  • Free

    Quantitative Aptitude Formulas for Placement Tests

    A formula sheet for the quantitative section of placement aptitude tests, from percentages and interest to time and work, speed, permutations, probability and number system, with a worked example for each topic.

    GuideWebBeginner

    FreeRead