Skip to content

Divide and Conquer: Code Templates in 6 Languages

If you have not read the concept guide yet, start there for the intuition and complexity analysis. This page gives you the code you can memorize and adapt during an interview. Every template follows the same skeleton: split the input, solve the pieces recursively, and combine the results.

Main Template: Merge Sort

Merge sort is the most common divide and conquer implementation interviewers ask you to write. It splits the array into halves, sorts each half, and merges the sorted halves back together. The merge step is what makes the whole thing work, so pay attention to it.

Use this for Sort an Array .

function mergeSort(arr, left = 0, right = arr.length - 1) {
    if (left >= right) return; // base case: range is empty or one element

    const mid = Math.floor((left + right) / 2);
    // Split: both halves must stay disjoint and cover the full range
    mergeSort(arr, left, mid);
    mergeSort(arr, mid + 1, right);

    // Combine: the halves are sorted, now merge them
    merge(arr, left, mid, right);
}

function merge(arr, left, mid, right) {
    // Copy both halves so the merge can write over the original
    // range without losing values it still has to compare
    const n1 = mid - left + 1;
    const n2 = right - mid;
    const leftArr = new Array(n1);
    const rightArr = new Array(n2);

    for (let i = 0; i < n1; i++) leftArr[i] = arr[left + i];
    for (let j = 0; j < n2; j++) rightArr[j] = arr[mid + 1 + j];

    let i = 0, j = 0, k = left;
    // Place the smaller current head of each half back into the array
    while (i < n1 && j < n2) {
        if (leftArr[i] <= rightArr[j]) arr[k++] = leftArr[i++];
        else arr[k++] = rightArr[j++];
    }
    // One half runs out first; the rest of the other is already in order
    while (i < n1) arr[k++] = leftArr[i++];
    while (j < n2) arr[k++] = rightArr[j++];
}
Templates only help if you can recall them without staring at the screen. Turn these snippets into flashcards for daily mobile review.

Code Breakdown

Key Variables

  • left and right: the range of the array the current call owns. Every recursive call narrows this range until it hits the base case.
  • mid: the boundary between the two halves, computed as the midpoint of left and right. Everything at or before mid belongs to the first half.
  • leftArr and rightArr (merge): temporary copies of the two sorted halves, needed so the merge can write over the original range without losing values it still has to read.
  • i, j, and k (merge): the read cursors for the left and right copies plus the write cursor for the original array. i and j advance when their element is placed, k advances on every write.

Visual Mechanism

    stateDiagram-v2
    [*] --> Split: sort both halves recursively
    Split --> Merge: both halves sorted
    Merge --> Done: write sorted merge back
    Done --> [*]
  

Critical Sections

The base case left >= right stops the recursion when the range has one element or fewer, and it is what prevents infinite recursion on empty input.

The split is just arithmetic. Because left and mid are inclusive and the second half starts at mid plus one, every element lands in exactly one half, which is why the off-by-one at this line matters.

The merge loop compares the current heads of both halves and writes the smaller one back into the original array. The two trailing loops exist because after one half is exhausted, the remainder of the other half is already in order and can be copied over directly.

The temporary arrays are not an optimization detail. Without them, writing the smaller element back would overwrite values the merge still needs to compare.

Variations

1. Quick Sort (In-Place Partition)

Quick sort sorts in place instead of merging. It partitions the segment around a pivot so that smaller elements land on the left and larger ones on the right, then recurses on both sides. The partition function below also powers quickselect in the next variation.

function quickSort(arr, low = 0, high = arr.length - 1) {
    if (low >= high) return;

    const pivotIndex = partition(arr, low, high);
    // The pivot is already in its final position, so recurse
    // on the sides around it
    quickSort(arr, low, pivotIndex - 1);
    quickSort(arr, pivotIndex + 1, high);
}

function partition(arr, low, high) {
    const pivot = arr[high]; // rightmost element as the pivot
    let i = low;
    for (let j = low; j < high; j++) {
        if (arr[j] < pivot) {
            // Move elements smaller than the pivot left,
            // everything else is pushed right implicitly
            [arr[i], arr[j]] = [arr[j], arr[i]];
            i++;
        }
    }
    // The pivot lands between the two groups
    [arr[i], arr[high]] = [arr[high], arr[i]];
    return i;
}

Visual

    graph TD
    A["Array segment"] --> B["Pick pivot (last element)"]
    B --> C["Swap smaller elements left"]
    C --> D["Pivot to its final position"]
    D --> E["Recurse on both sides"]
  

2. Quickselect (Kth Largest Element)

Quickselect borrows the partition step but recurses into only one side, the side that contains the target index. That pruning is what drops the average cost to linear. For the kth largest element, the target index in sorted order is the array length minus k.

Use this for Kth Largest Element in an Array .

function findKthLargest(nums, k) {
    // The kth largest value sits at index n-k once the array is sorted
    const target = nums.length - k;
    let low = 0, high = nums.length - 1;

    while (low <= high) {
        const pivotIndex = partition(nums, low, high);
        // Follow only the branch that contains the target index,
        // which is why quickselect averages O(N) instead of O(N log N)
        if (pivotIndex === target) return nums[pivotIndex];
        if (pivotIndex < target) low = pivotIndex + 1;
        else high = pivotIndex - 1;
    }
}

function partition(nums, low, high) {
    const pivot = nums[high];
    let i = low;
    for (let j = low; j < high; j++) {
        if (nums[j] < pivot) {
            [nums[i], nums[j]] = [nums[j], nums[i]];
            i++;
        }
    }
    [nums[i], nums[high]] = [nums[high], nums[i]];
    return i;
}

Visual

    graph TD
    A["Partition around pivot"] --> B{"Pivot index == target?"}
    B -->|Yes| C["Return pivot value"]
    B -->|No| D{"Pivot index < target?"}
    D -->|Yes| E["Search right half"]
    D -->|No| F["Search left half"]
    E --> A
    F --> A
  
Each variation above is a separate review card in the app. Drill them individually so you do not mix up the conditions under pressure.

Now head to the practice problems to apply these templates to real interview questions.

Now that you have the templates, the next step is application. Head to the practice problems or start reviewing these templates with spaced repetition .