Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
For each element, shift the larger elements of the sorted prefix one step right and drop the element into the gap. O(n²) worst, O(n) on nearly-sorted input.
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you implement shift-and-insert and know its adaptivity to sorted input.
Where candidates slip
Losing the key by not saving it, or an off-by-one placement.
How to stand out
Note it's stable, adaptive (O(n) on sorted), and used inside Timsort.
Choose
Compare the available approaches
Use constraints and trade-offs to select the route you can defend in an interview.
Learn & trace
Build each solution step by step
Move from the core idea to a visual trace, implementation, proof, and edge cases.
Approach 1 of 1 · Optimal
Shift-and-insert
1Hint 1Explore hintHide hint
Treat the left part as sorted — where does the next element belong?
2Hint 2Explore hintHide hint
Shift larger sorted elements right to open a gap, then insert the key.
3Hint 3Explore hintHide hint
What happens on already-sorted input?
A · Core idea
Insertion sort grows a sorted prefix by taking each next element (the 'key') and shifting the larger sorted elements one step right to open a slot, then dropping the key in.
Why it's great on nearly-sorted data. If the key is already ≥ the prefix's last element, no shifting happens — so on an (almost) sorted array each insertion is O(1), giving near-linear O(n) total. This adaptivity is its real strength and why it's used as the base case inside fast sorts (e.g. Timsort).
Why save the key first. The shifting overwrites positions, so you must capture key = nums[i] before sliding elements, then place it in the opened gap at j+1.
Stable, in place, O(n²) worst. On reverse-sorted input every element shifts the whole prefix → O(n²); but it's stable and O(1) space.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
nums = [3, 1, 2]key=1
shift 3 right, insert 1
[1,3,2][1, 2, 3]C · Code with teaching comments
D · Why it works and complexityO(n²) timeO(1) spaceOpen the invariant and proofExplore the proofHide the proof
ComplexityO(n²) time, O(1) space — worst case shifts the whole prefix each time → O(n²); on nearly-sorted data few shifts → O(n).
E · Edge cases and pitfalls5nums = [1, 2, 3] — Already sorted → O(n), no shifts.Explore edge casesHide edge cases
Edge cases handled
nums = [1, 2, 3]Already sorted → O(n), no shifts.nums = [2, 1]One insert → [1, 2].nums = [3, 2, 1]Reverse → worst-case O(n²).
Pitfalls
- Overwriting the key before shifting (save it first).
- Off-by-one when placing the key (j+1).
Practice
Try the solution yourself
Edit the optimal implementation, test another input, and observe the result.
Editable code previewpublic void insertionSort(int[] nums) { for (int i = 1; i < nums.length; i++) { int key = nums[i]; int j = i - 1; while (j >= 0 && nums[j] > key) {Explore the playgroundClose the playground
Avoid mistakes
Recognize the interview traps
Understand why common attempts fail before reviewing the corrected implementation.
- Overwriting the key before shifting (save it first).
- Off-by-one when placing the key (j+1).
Revise
Carry the pattern into the interview
Pattern to remember
Shift-and-insert
Code pattern to memorize
for i: key=a[i]; shift a[j]>key right; a[j+1]=keyRules to remember
- 1Sorted prefix grows.
- 2Shift larger elements right.
- 3Fast on nearly-sorted data.
Use this pattern when
- Nearly-sorted data
- Base case of hybrid sorts
Interview takeaway
Insertion sort shines when the data is almost sorted.
Continue
Transfer the pattern to another problem
Use a direct variation or pattern sibling to prove the idea is reusable.
Transferable patternA core fresher pattern: Shift-and-insert. Master it on small inputs and it transfers to harder problems.
Practice queueDirect variations and pattern siblings
Direct follow-ups