next_permutation, rotate & reverse

RoadmapsC++

Scenario

An interviewer asks you to write a function that takes an array like `[1, 2, 3, 4, 5]` and shifts it left by 2 spaces, resulting in `[3, 4, 5, 1, 2]`. You start writing a temporary array, a loop, and some complex modulo math.

Is there a single STL function that does this in-place with zero extra memory?

Mental model

The `<algorithm>` header is a Swiss Army Knife. Instead of writing custom loops to flip, shift, or permute data, you just pull out the exact specialized tool for the job. It's faster, bug-free, and instantly communicates your intent to other engineers.

C++ provides highly optimized in-place algorithms for sequence manipulation. `std::reverse` flips a sequence. `std::rotate` shifts elements circularly. `std::next_permutation` is a "magic" algorithm that rearranges elements into their next lexicographically greater permutation, making brute-force combinatorics trivial.

Explanation

**1. std::reverse**

`std::reverse(begin, end)` flips the elements in the range in O(N) time. Simple, but incredibly useful when combined with other algorithms (like sorting in descending order, though `rbegin` is better for that).

**2. std::rotate**

`std::rotate(first, new_first, last)` performs a circular shift. The element at `new_first` becomes the new beginning of the sequence. It works in-place (O(1) auxiliary space) and takes O(N) time. It's notoriously tricky to implement manually without bugs, so always use the STL version.

**3. std::next_permutation**

`std::next_permutation(begin, end)` modifies the array into the next lexicographical permutation and returns `true`. If the array is sorted in descending order (the absolute last permutation), it wraps around to ascending order and returns `false`. This allows you to generate all possible permutations with a simple `do { ... } while(next_permutation(...))` loop.

**Real-world Engineering:**

These tools replace hundreds of lines of boilerplate. `std::rotate` is used in text editors to shift blocks of text or in UI carousels. `std::next_permutation` is widely used in competitive programming and operations research to brute-force small Traveling Salesperson variations without writing complex recursive backtracking.

Code examples

Generating all permutations

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 3};
    
    // vec MUST be sorted initially to guarantee we hit all permutations
    std::sort(vec.begin(), vec.end());
    
    int count = 0;
    do {
        count++;
        // The vector is modified in-place to the next permutation
    } while (std::next_permutation(vec.begin(), vec.end()));
    
    std::cout << "Total permutations: " << count << '\n'; // Prints 6
    return 0;
}

This loop generates all 3! (6) permutations without any recursion, manual swapping, or extra memory allocation.

Left Rotation

#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    
    // We want the element at index 2 (the '3') to become the new front.
    // v.begin() + 2 is the 'new_first' iterator.
    std::rotate(v.begin(), v.begin() + 2, v.end());
    
    // v is now {3, 4, 5, 1, 2}
    return 0;
}

`std::rotate` handles the complex block-swapping logic internally, ensuring O(N) speed with zero dynamic memory allocation.

Key points

Common mistakes

Recall questions

Questions & answers

A developer writes a `while(std::next_permutation(...))` loop to test all possible combinations of a 5-element array. The array starts as `[5, 1, 4, 2, 3]`. Will the loop test all 120 (5!) permutations? Why?

No. The loop will only test the permutations lexicographically greater than `[5, 1, 4, 2, 3]`. Because it wasn't sorted ascending first, a large chunk of permutations (anything starting with 1, 2, 3, or 4) will be completely skipped.

Approach: Understand the lexicographical prerequisite for permutation generation.

How can you use `std::rotate` to move the first element of a vector to the very end while shifting everything else left?

You call `std::rotate(vec.begin(), vec.begin() + 1, vec.end())`. The element at `vec.begin() + 1` becomes the new first element, which effectively shifts the old first element to the back.

Approach: Understand the iterator boundaries required to perform basic shifts.

Continue learning

Previous: sort, binary_search, lower_bound & upper_bound

Return to C++ Roadmap