githubEdit

09. Largest Number in One Swap

βœ… GFG solution to the Largest Number in One Swap problem: find the lexicographically largest string by swapping at most one pair of characters using greedy last-occurrence tracking. πŸš€

The problem can be found at the following link: πŸ”— Question Linkarrow-up-right

🧩 Problem Description

Given a string s consisting of digit characters, return the lexicographically largest string that can be obtained by swapping at most one pair of characters in s.

If no beneficial swap exists (i.e., the string is already the largest possible), return the string as-is.

πŸ“˜ Examples

Example 1

Input: s = "768"
Output: "867"
Explanation: Swapping the 1st and 3rd characters (7 and 8) gives the lexicographically largest string "867".

Example 2

Input: s = "333"
Output: "333"
Explanation: All characters are identical; any swap yields the same result.

πŸ”’ Constraints

  • $1 \le |s| \le 10^5$

  • $\text{'0'} \le s[i] \le \text{'9'}$

βœ… My Approach

The optimal approach uses a Greedy Last-Occurrence Array strategy to find the best possible single swap in one pass:

Greedy + Last Occurrence Array

  1. Precompute Last Positions:

    • Build an array last[0..9] where last[d] stores the last index at which digit d appears in the string.

    • This allows O(1) lookup: "does digit d appear after position i?"

  2. Scan Left to Right:

    • For each position i, try digits from 9 down to s[i] + 1 (larger digits only).

    • If a digit d exists at some index last[d] > i, then swapping s[i] with s[last[d]] places the largest possible digit at the earliest possible position.

  3. Perform the Swap and Return:

    • As soon as a valid beneficial swap is found, perform it and immediately return.

    • This greedy choice is optimal β€” we always maximise the most significant digit first.

  4. No Swap Needed:

    • If no beneficial swap is found after scanning all positions, the string is already at its maximum; return it unchanged.

πŸ“ Time and Auxiliary Space Complexity

  • Expected Time Complexity: O(n), where n is the length of the string. We make one linear pass to build the last-occurrence array and at most one more linear scan with a constant inner loop of 10 digits, giving O(10n) = O(n) overall.

  • Expected Auxiliary Space Complexity: O(1), as we only use a fixed-size array of 10 elements to track digit positions, regardless of the input size.

πŸ§‘β€πŸ’» Code (C++)

chevron-right⚑ View Alternative Approaches with Code and Analysishashtag

πŸ“Š 2️⃣ Right-to-Left Max Tracking

πŸ’‘ Algorithm Steps:

  1. Traverse from right to left, maintaining a running max digit and its index.

  2. Whenever a digit smaller than the current max is found, record it as a candidate swap pair.

  3. After full traversal, the last recorded pair gives the leftmost beneficial swap.

  4. Perform the swap if a valid pair was found.

πŸ“ Complexity Analysis:

  • Time: ⏱️ O(n) – Single right-to-left pass through all characters

  • Auxiliary Space: πŸ’Ύ O(1) – Constant number of tracking variables only

βœ… Why This Approach?

  • Simple single-pass logic with no nested loops

  • Minimal variable usage β€” no auxiliary arrays

  • Excellent for interview whiteboard clarity

πŸ“Š 3️⃣ Digit Frequency Greedy

πŸ’‘ Algorithm Steps:

  1. Count the frequency of each digit (0–9) in the string.

  2. From left to right, at each position check if any larger digit exists anywhere after it using the frequency count.

  3. Among all positions of that larger digit, prefer the rightmost one (to preserve future positions).

  4. Perform the swap immediately and return.

πŸ“ Complexity Analysis:

  • Time: ⏱️ O(10n) = O(n) – Outer position loop with a constant 10-digit inner check

  • Auxiliary Space: πŸ’Ύ O(1) – Fixed-size digit frequency array of length 10

βœ… Why This Approach?

  • Explicit digit frequency reasoning makes the greedy logic very transparent

  • Easy to extend for multi-swap variants

  • Good for demonstrating greedy thinking step-by-step

πŸ†š πŸ” Comparison of Approaches

πŸš€ Approach

⏱️ Time

πŸ’Ύ Space

βœ… Pros

⚠️ Cons

🏷️ Last Occurrence Array

🟒 O(n)

🟒 O(1)

πŸš€ Fastest single-pass greedy

πŸ”§ Needs last-index precomputation

πŸ”„ Right-to-Left Max Track

🟒 O(n)

🟒 O(1)

πŸ“– Intuitive single pass

⚠️ Subtle candidate update logic

πŸ”’ Digit Frequency Greedy

🟒 O(n)

🟒 O(1)

⭐ Very explicit digit reasoning

πŸ”§ More lines, nested loops

πŸ† Best Choice Recommendation

🎯 Scenario

πŸŽ–οΈ Recommended Approach

πŸ”₯ Rating

πŸ… Optimal performance

πŸ₯‡ Last Occurrence Array

β˜…β˜…β˜…β˜…β˜…

πŸ“– Readability priority

πŸ₯ˆ Right-to-Left Max Track

β˜…β˜…β˜…β˜…β˜†

🎯 Interview / Competitive

πŸ… Last Occurrence Array

β˜…β˜…β˜…β˜…β˜…

β˜• Code (Java)

🐍 Code (Python)

🧠 Contribution and Support

For discussions, questions, or doubts related to this solution, feel free to connect on LinkedIn: πŸ“¬ Any Questions?arrow-up-right. Let's make this learning journey more collaborative!

⭐ If you find this helpful, please give this repository a star! ⭐


πŸ“Visitor Count

Visitor counter

Last updated