Skip to content
Bill Liao
Go back

Merge Sort

Edit page

Merge Sort is a classic divide and conquer sorting algorithm. Given an array of integers nums, sort the array in ascending order in O(n log n) time.

Example 1:

Input: nums = [5,2,3,1] Output: [1,2,3,5]

Example 2:

Input: nums = [5,1,1,2,0,0] Output: [0,0,1,1,2,5]

Approach: Merge Sort (Divide and Conquer)

Algorithm

  1. Divide: Recursively split the array into two halves until each half has a single element
  2. Conquer: A single-element array is trivially sorted
  3. Combine: Merge two sorted halves into one sorted array by repeatedly taking the smaller head
  4. Repeat until the whole array is merged

Time & Space Complexity

Java Implementation

public class MergeSort {

    /**
     * Sort an array in ascending order using merge sort.
     * @param nums Input array
     * @return Sorted array
     */
    public static int[] sortArray(int[] nums) {
        int[] temp = new int[nums.length];
        mergeSort(nums, temp, 0, nums.length - 1);
        return nums;
    }

    private static void mergeSort(int[] nums, int[] temp, int lo, int hi) {
        if (lo >= hi) {
            return;
        }

        int mid = lo + (hi - lo) / 2;
        mergeSort(nums, temp, lo, mid);
        mergeSort(nums, temp, mid + 1, hi);
        merge(nums, temp, lo, mid, hi);
    }

    private static void merge(int[] nums, int[] temp, int lo, int mid, int hi) {
        for (int i = lo; i <= hi; i++) {
            temp[i] = nums[i];
        }

        int i = lo;
        int j = mid + 1;
        int k = lo;

        while (i <= mid && j <= hi) {
            if (temp[i] <= temp[j]) {
                nums[k++] = temp[i++];
            } else {
                nums[k++] = temp[j++];
            }
        }

        while (i <= mid) {
            nums[k++] = temp[i++];
        }
        while (j <= hi) {
            nums[k++] = temp[j++];
        }
    }

    // Test method
    public static void main(String[] args) {
        int[] nums1 = {5, 2, 3, 1};
        System.out.println("Input: nums = [5, 2, 3, 1]");
        System.out.println("Output: " + java.util.Arrays.toString(sortArray(nums1)));
        // Expected: [1, 2, 3, 5]

        int[] nums2 = {5, 1, 1, 2, 0, 0};
        System.out.println("Input: nums = [5, 1, 1, 2, 0, 0]");
        System.out.println("Output: " + java.util.Arrays.toString(sortArray(nums2)));
        // Expected: [0, 0, 1, 1, 2, 5]
    }
}

Example Walkthrough

For nums = [5, 2, 3, 1]:

  1. Split: [5, 2] and [3, 1]
  2. Split again: [5], [2], [3], [1]
  3. Merge [5] and [2] -> [2, 5]
  4. Merge [3] and [1] -> [1, 3]
  5. Merge [2, 5] and [1, 3] -> [1, 2, 3, 5]

Key Points

  1. Stable: Equal elements keep their relative order
  2. Guaranteed O(n log n): Performance does not depend on the input distribution
  3. Not In-Place: Requires O(n) extra space for the merge step
  4. Predicate: Used in advanced problems like counting inversions and “Count of Smaller Numbers After Self”
  5. Recursion Base Case: Arrays of size 0 or 1 are already sorted

Edit page
Share this post:

Previous Post
Kth Largest Element in an Array
Next Post
Quick Sort