string manipulation
lexicographic order
substring reversal
algorithm techniques
programming challenges

How to find the lexicographically smallest string by reversing a substring?

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

In the realm of string manipulation, one interesting problem is finding the lexicographically smallest string by reversing exactly one contiguous substring. This problem has applications in genetic data analysis, text processing, and competitive programming. The goal is to determine the smallest possible string achievable through a single reversal operation.

Understanding Lexicographical Order

Lexicographical order is the generalization of dictionary order to strings. Given two strings s1 and s2, s1 is lexicographically smaller than s2 if, at the first position where they differ, the character in s1 comes before the character in s2 alphabetically.

For example:

  • "abc" is smaller than "abd" (differ at position 2: 'c' < 'd')
  • "a" is smaller than "aa" (first string is a prefix, and shorter)

Problem Statement

Given a string, find the smallest possible string by reversing exactly one of its substrings. A substring is a contiguous sequence of characters. Note that reversing a substring of length 1 (or length 0) effectively means "no change," so the original string is always a valid candidate.

Brute Force Solution

The straightforward approach considers all possible substrings:

  1. For each pair of indices (i,j)(i, j) where 0i<jn0 \leq i < j \leq n, reverse the substring from index ii to jj.
  2. Compare the resulting string with the current minimum.
  3. Return the smallest string found.
python
1def find_lexicographically_smallest(s):
2    min_string = s
3    n = len(s)
4
5    for i in range(n):
6        for j in range(i + 1, n):
7            reversed_substring = s[i:j+1][::-1]
8            new_string = s[:i] + reversed_substring + s[j+1:]
9            if new_string < min_string:
10                min_string = new_string
11
12    return min_string

Complexity

  • Time: O(n3)O(n^3), because there are O(n2)O(n^2) pairs and each string comparison/reversal takes O(n)O(n).
  • Space: O(n)O(n) for storing the reversed string.

Optimized Approach

The brute force is impractical for large strings. A key observation enables a much faster solution:

Observation: To minimize the string lexicographically, you want the smallest possible character as early as possible. The optimal reversal must bring a smaller character to an earlier position.

Greedy Algorithm

  1. Scan left to right. Find the first position ii where s[i]s[i] is not the smallest character in s[i:]s[i:].
  2. Find the rightmost occurrence of the smallest character in s[i:]s[i:]. Call this position jj.
  3. Reverse s[i..j]s[i..j].

This works because the reversal brings the smallest available character to the earliest "imperfect" position, and taking the rightmost occurrence ensures that if there are ties, the characters between ii and jj are sorted in the best possible order after reversal.

python
1def find_smallest_optimized(s):
2    s = list(s)
3    n = len(s)
4
5    for i in range(n):
6        min_char = min(s[i:])
7        if s[i] != min_char:
8            # Find rightmost occurrence of min_char
9            j = n - 1
10            while s[j] != min_char:
11                j -= 1
12            # Reverse s[i..j]
13            s[i:j+1] = s[i:j+1][::-1]
14            break
15
16    return ''.join(s)

This runs in O(n)O(n) for finding the optimal reversal point, plus O(n)O(n) for the reversal itself, giving O(n)O(n) overall.

Worked Example

Original string: "cab"

Brute force enumeration:

Indices (i,j)(i, j)Original SubstringReversedResulting StringSmaller than "cab"?
(0, 1)"ca""ac""acb"Yes
(0, 2)"cab""bac""bac"Yes
(1, 2)"ab""ba""cba"No

The smallest result is "acb", achieved by reversing indices (0, 1).

Greedy approach: At position 0, the smallest character in "cab" is 'a' at index 1. Reverse s[0..1] to get "acb". Same answer, found in one scan.

Edge Cases

  • Already sorted: If the string is already the lexicographically smallest (e.g., "abc"), no reversal improves it.
  • All identical characters: Any reversal produces the same string, so the original is returned.
  • Single character: The string is already minimal.

Summary

ApproachTime ComplexitySpace ComplexityPractical for
Brute forceO(n3)O(n^3)O(n)O(n)Small strings (n < 1000)
GreedyO(n)O(n)O(n)O(n)Any string length

Finding the lexicographically smallest string by reversing a substring comes down to identifying where the string first deviates from sorted order and reversing just enough to bring the smallest available character forward. The greedy approach achieves this in linear time, making it practical for large inputs.


Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.