DSA Tracker

Problem

Medium

Nearly sorted

A medium Sorting interview guide. Task statement, worked examples, intuition, and step-by-step solutions.

Topic
Sorting
Sheets
1
Core for
13 roles

The problem

The array is almost in order: every element is at most k positions away from where it belongs. Put it fully in order, using that promise to do better than a general-purpose sort.

Example 1

Input
nums = [6, 5, 3, 2, 8, 10, 9], k = 3
Output
[2, 3, 5, 6, 8, 9, 10]
Why
Each element is at most 3 positions away from where it should be in the sorted array.

Example 2

Input
nums = [2, 1, 3, 1, 2], k = 1
Output
[1, 1, 2, 2, 3]

Constraints

  • 1 <= nums.length <= 10^5
  • 0 <= k <= nums.length
  • -10^5 <= nums[i] <= 10^5

How to think about it

Updated 2026-09-29

The guarantee that every item is at most k steps away means the true global minimum cannot hide in the distant tail; it must sit somewhere in the first k + 1 items. By maintaining a sliding window of size k + 1 in a min-heap, extracting the minimum always produces the definitive next element of the sorted output.

Approaches, worst first

  1. Unconstrained full sort

    time O(n log n) · space O(1)

    Ignore the distance parameter k and sort the entire array with standard quicksort or timsort. Simple, but pays O(n log n) overhead by failing to capitalize on the strong locality guarantee.

  2. Insertion sort within window

    time O(n * k) · space O(1)

    Run insertion sort knowing each element shifts backward at most k steps. Each insertion takes O(k) comparisons, yielding an O(n * k) overall runtime that is very fast for tiny k but degrades if k scales toward n.

  3. Min-heap sliding windowWrite this one

    time O(n log k) · space O(k)

    Push the first k + 1 elements into a min-heap. Pop the minimum to write to the result, push the next input element, and repeat until the array is consumed, then drain the heap. The heap never exceeds k + 1 elements.

Where people lose marks · 3
  • Sizing the initial heap to k instead of k + 1: an element at index k could belong at index 0, so the candidate pool for the first position requires all k + 1 initial items.
  • When k = 0, the array is already sorted; handling k = 0 with a window of size 1 must not crash or trigger empty heap access.
  • Forgetting to empty the remaining items from the min-heap after reaching the end of the input array leaves the final k elements missing from the sorted output.

Full solution

C++
#include <bits/stdc++.h>
using namespace std;

vector<int> nearlySorted(vector<int>& arr, int k) {
    priority_queue<int, vector<int>, greater<int>> pq;
    vector<int> out;
    out.reserve(arr.size());
    for (int i = 0; i <= k && i < (int)arr.size(); i++) {
        pq.push(arr[i]);
    }
    for (int i = k + 1; i < (int)arr.size(); i++) {
        out.push_back(pq.top());
        pq.pop();
        pq.push(arr[i]);
    }
    while (!pq.empty()) {
        out.push_back(pq.top());
        pq.pop();
    }
    return out;
}
Java
import java.util.*;

public class Main {
    static int[] nearlySorted(int[] arr, int k) {
        PriorityQueue<Integer> pq = new PriorityQueue<>();
        int[] out = new int[arr.length];
        int idx = 0;
        for (int i = 0; i <= k && i < arr.length; i++) {
            pq.offer(arr[i]);
        }
        for (int i = k + 1; i < arr.length; i++) {
            out[idx++] = pq.poll();
            pq.offer(arr[i]);
        }
        while (!pq.isEmpty()) {
            out[idx++] = pq.poll();
        }
        return out;
    }
}
Python
def nearly_sorted(arr, k):
    import heapq
    heap = arr[:k + 1]
    heapq.heapify(heap)
    out = []
    for value in arr[k + 1:]:
        out.append(heapq.heappop(heap)); heapq.heappush(heap, value)
    while heap: out.append(heapq.heappop(heap))
    return out
JavaScript
function nearlySorted(arr) {
  return [...arr].sort((a, b) => a - b);
}
Try it in the editor

The theory behind it

Sorting — the ground this problem stands on. All Sorting problems

What Sorting is

Sorting is the act of arranging a scrambled hand of playing cards into ascending rank from left to right. It reorganizes scattered data according to a consistent comparison rule, like numbering index cards or alphabetizing names. While unsorted data requires searching every single entry to verify whether an item exists, ordered data establishes predictable relationships that make duplicates, clusters, and extreme values immediately visible.

When to reach for it

Reach for sorting when a problem asks to group identical items, detect overlaps among intervals, find rank percentiles, or pair values matching a target sum. If an unordered problem appears intractable in polynomial time, sorting the input frequently unlocks linear scans or two-pointer sweeps. When an O(n log n) preprocessing step simplifies downstream matching logic, sorting is usually the right opening move.

How the pattern works

Think of sorting as a trade: invest logarithmic overhead upfront to make subsequent queries direct and orderly. Compare adjacent elements to uncover duplicate entries, or march inward from outer boundaries once elements stand in monotonic sequence. When designing custom comparators, confirm strict weak ordering by verifying reflexivity, antisymmetry, and transitivity; inconsistent comparison logic breaks internal pivot partitions or produces corrupted outputs.

More Sorting problems

Asked at

Track in your role's order

Pick your target role and all 370 problems resequence to what that interview actually asks.

Start free

Problem set and role mapping as of .