Maximize permutations

Last Updated : 2 Jun, 2026

Given two strings n and m representing non-negative integers, find the largest number that can be formed by rearranging the digits of n such that the resulting number is less than or equal to m.

  • Each digit of n must be used exactly once, and the resulting number must not contain leading zeros.
  • If no such arrangement is possible, return "-1".
  • The answer should be returned as a string.

Examples:

Input: n = "123", m = "222"
Output: "213"
Explanation: The permutations of "123" are "123", "132", "213", "231", "312", and "321". Among these, "123", "132", and "213" are less than or equal to "222". Therefore, the answer is "213".

Input: n = "3921", m = "10000"
Output: "9321"
Explanation: Since n has fewer digits than m, every permutation of "3921" is less than "10000". The maximum permutation is "9321".

Try It Yourself
redirect icon

[Naive Approach] Generate All Permutations - O(|n|!) Time and O(n) Space

The idea is to generate all possible permutations of the digits of n using recursion (backtracking). For each permutation, we check whether it is valid, i.e., it has no leading zeros and is less than or equal to m. Among all valid permutations, we maintain the maximum one using a global variable.

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

// Global variable to store answer
string res;

// Function to generate all permutations
void solve(string &digits, string &cur, vector<bool> &used, string &m) {

    // Base case: full permutation formed
    if (cur.size() == digits.size()) {

        // Avoid leading zero numbers
        if (cur.size() > 1 && cur[0] == '0')
            return;

        // Check if current permutation is valid (<= m)
        if (cur.size() < m.size() ||
           (cur.size() == m.size() && cur <= m)) {

            // Update result if current is greater
            if (res == "-1" || cur > res) {
                res = cur;
            }
        }

        return;
    }

    // Try every unused digit
    for (int i = 0; i < digits.size(); i++) {

        if (used[i])
            continue;

        used[i] = true;
        cur.push_back(digits[i]);

        solve(digits, cur, used, m);

        // Backtracking
        cur.pop_back();
        used[i] = false;
    }
}

// Function to find maximum permutation <= m
string maxPerm(string &n, string &m) {

    vector<bool> used(n.size(), false);
    string cur = "";

    res = "-1";

    solve(n, cur, used, m);

    return res;
}

int main() {

    string n = "123";
    string m = "222";

    cout << maxPerm(n, m);

    return 0;
}
Java
public class GFG {

    // Global variable to store answer
    static String res = "-1";

    // Function to generate all permutations
    static void solve(String digits, String cur, boolean[] used, String m) {

        // Base case: full permutation formed
        if (cur.length() == digits.length()) {

            // Avoid leading zero numbers
            if (cur.length() > 1 && cur.charAt(0) == '0')
                return;

            // Check if current permutation is valid (<= m)
            if (cur.length() < m.length() ||
               (cur.length() == m.length() && cur.compareTo(m) <= 0)) {

                // Update result if current is greater
                if (res.equals("-1") || cur.compareTo(res) > 0) {
                    res = cur;
                }
            }

            return;
        }

        // Try every unused digit
        for (int i = 0; i < digits.length(); i++) {

            if (used[i]) continue;

            used[i] = true;

            solve(digits, cur + digits.charAt(i), used, m);

            used[i] = false;
        }
    }

    // Function to find maximum permutation <= m
    static String maxPerm(String n, String m) {

        boolean[] used = new boolean[n.length()];
        res = "-1";

        solve(n, "", used, m);

        return res;
    }

    public static void main(String[] args) {

        String n = "123";
        String m = "222";

        System.out.println(maxPerm(n, m));
    }
}
Python
# Global variable to store answer
res = "-1"

# Function to generate all permutations
def solve(digits, cur, used, m):

    global res

    # Base case: full permutation formed
    if len(cur) == len(digits):

        # Avoid leading zero numbers
        if len(cur) > 1 and cur[0] == '0':
            return

        # Check if current permutation is valid (<= m)
        if len(cur) < len(m) or (len(cur) == len(m) and cur <= m):

            # Update result if current is greater
            if res == "-1" or cur > res:
                res = cur

        return

    # Try every unused digit
    for i in range(len(digits)):

        if used[i]:
            continue

        used[i] = True
        solve(digits, cur + digits[i], used, m)
        used[i] = False


# Function to find maximum permutation <= m
def maxPerm(n, m):

    global res

    used = [False] * len(n)
    res = "-1"

    solve(n, "", used, m)

    return res

if __name__ == "__main__":

    n = "123"
    m = "222"

    print(maxPerm(n, m))
C#
using System;

class GFG
{
    // Global variable to store answer
    static string res = "-1";

    // Function to generate all permutations
    static void solve(char[] digits, string cur, bool[] used, string m)
    {
        // Base case: full permutation formed
        if (cur.Length == digits.Length)
        {
            // Avoid leading zero numbers
            if (cur.Length > 1 && cur[0] == '0')
                return;

            // Check if current permutation is valid (<= m)
            if (cur.Length < m.Length ||
               (cur.Length == m.Length && string.Compare(cur, m) <= 0))
            {
                // Update result if current is greater
                if (res == "-1" || string.Compare(cur, res) > 0)
                {
                    res = cur;
                }
            }

            return;
        }

        // Try every unused digit
        for (int i = 0; i < digits.Length; i++)
        {
            if (used[i]) continue;

            used[i] = true;

            solve(digits, cur + digits[i], used, m);

            // Backtracking
            used[i] = false;
        }
    }

    // Function to find maximum permutation <= m
    static string maxPerm(string n, string m)
    {
        char[] digits = n.ToCharArray();
        bool[] used = new bool[n.Length];

        res = "-1";

        solve(digits, "", used, m);

        return res;
    }

    static void Main()
    {
        string n = "123";
        string m = "222";

        Console.WriteLine(maxPerm(n, m));
    }
}
JavaScript
let res = "-1";

// Function to generate all permutations
function solve(digits, cur, used, m) {

    // Base case: full permutation formed
    if (cur.length === digits.length) {

        // Avoid leading zero numbers
        if (cur.length > 1 && cur[0] === '0')
            return;

        // Check if current permutation is valid (<= m)
        if (cur.length < m.length ||
           (cur.length === m.length && cur <= m)) {

            // Update result if current is greater
            if (res === "-1" || cur > res) {
                res = cur;
            }
        }

        return;
    }

    // Try every unused digit
    for (let i = 0; i < digits.length; i++) {

        if (used[i]) continue;

        used[i] = true;

        solve(digits, cur + digits[i], used, m);

        // Backtracking
        used[i] = false;
    }
}

// Function to find maximum permutation <= m
function maxPerm(n, m) {

    let digits = n.split("");
    let used = new Array(n.length).fill(false);

    res = "-1";

    solve(digits, "", used, m);

    return res;
}

// Driver code
let n = "123";
let m = "222";
console.log(maxPerm(n, m));

Output
213

[Expected Approach] Greedy Digit Construction - O(|n|log|n|) Time and O(1) Space

Instead of generating all permutations of the digits of n, we build the answer greedily from left to right. The key idea is to always try to match the current digit of m using available digits from n. If at some position we cannot exactly match m, we try to place the largest possible smaller digit at that position and then maximize the remaining suffix by arranging all remaining digits in descending order.

Consider: n = "123", m = "222"

Step 1: We first store the frequency of digits present in n.

  • freq[1] = 1
  • freq[2] = 1
  • freq[3] = 1

Step 2: Start matching with m

We try to build number digit by digit.

For i = 0

  • m[i] = '2'
  • Available digits in n: {1, 2, 3}
  • We try to match '2' and it is available, so we use it.
  • At the same time, we check if a smaller digit can be placed.
  • Smaller digit available = 1
  • So we store: bestIndex = 0, bestDigit = 1

For i = 1

  • m[i] = '2'
  • Available digits: {1, 3}
  • We cannot match digit 2 anymore
  • So exact matching with m fails here
  • Now we check for the best possible smaller digit than 2:
  • Available smaller digit = 1
  • So we store: bestIndex = 1, bestDigit = 1

Step 3: Construct final answer using break point

  • We build the result as follows:
  • Take prefix of m up to bestIndex -> "2"
  • Place bestDigit -> "1"
  • So far: res = "21"

Step 4: Add remaining digits

  • Remaining digit = 3
  • We place remaining digits in descending order: res = "213"

Final Answer: "213"

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

string maxPerm(string &n, string &m) {

    // If n has more digits than m, no valid
    // permutation is possible
    if (n.length() > m.length()) {
        return "-1";
    }

    // If n has fewer digits than m, return 
    // the largest permutation
    if (n.length() < m.length()) {
        sort(n.begin(), n.end());

        string res = "";
        for (int i = n.length() - 1; i >= 0; i--) {
            res += n[i];
        }

        return res;
    }

    int len = n.length();
    vector<int> freq(10, 0);

    // Count frequency of digits in n
    for (char c : n) {
        freq[c - '0']++;
    }

    int bestIndex = -1;
    int bestDigit = -1;
    bool exactMatch = true;

    // Try to construct the answer from left to right
    for (int i = 0; i < len; i++) {

        int limitDigit = m[i] - '0';
        int chosenDigit = -1;

        // Find largest available digit smaller 
        // than limitDigit
        for (int d = limitDigit - 1; d >= 0; d--) {

            if (freq[d] > 0) {

                // Avoid leading zero
                if (i == 0 && d == 0) continue;

                chosenDigit = d;
                break;
            }
        }

        // Store best break position
        if (chosenDigit != -1) {
            bestIndex = i;
            bestDigit = chosenDigit;
        }

        // Try to match current digit of m
        int matchDigit = m[i] - '0';

        if (freq[matchDigit] > 0) {
            freq[matchDigit]--;
        } else {
            exactMatch = false;
            break;
        }
    }

    // If exact match exists
    if (exactMatch) {
        return m;
    }

    // Build answer using best break point
    if (bestIndex != -1) {

        string res = "";

        // Prefix from m
        for (int i = 0; i < bestIndex; i++) {
            res += m[i];
        }

        // Add best smaller digit
        res += char('0' + bestDigit);

        vector<int> remaining(10, 0);

        // Rebuild frequency
        for (char c : n) {
            remaining[c - '0']++;
        }

        // Remove prefix digits
        for (int i = 0; i < bestIndex; i++) {
            remaining[m[i] - '0']--;
        }

        // Remove chosen digit
        remaining[bestDigit]--;

        // Fill remaining digits in descending order
        for (int d = 9; d >= 0; d--) {
            while (remaining[d] > 0) {
                res += char('0' + d);
                remaining[d]--;
            }
        }

        return res;
    }

    return "-1";
}

int main() {

    string n, m;

    n = "123";
    m = "222";

    cout << maxPerm(n, m) << endl;

    return 0;
}
Java
import java.util.*;

public class GFG {

    static String maxPerm(String n, String m) {

        // If n has more digits than m, no valid 
        // permutation is possible
        if (n.length() > m.length()) {
            return "-1";
        }

        // If n has fewer digits than m, return
        // the largest permutation
        if (n.length() < m.length()) {

            char[] arr = n.toCharArray();
            Arrays.sort(arr);

            String res = "";
            for (int i = arr.length - 1; i >= 0; i--) {
                res += arr[i];
            }

            return res;
        }

        int len = n.length();
        int[] freq = new int[10];

        // Count frequency of digits in n
        for (char c : n.toCharArray()) {
            freq[c - '0']++;
        }

        int bestIndex = -1;
        int bestDigit = -1;
        boolean exactMatch = true;

        // Try to construct the answer from left to right
        for (int i = 0; i < len; i++) {

            int limitDigit = m.charAt(i) - '0';
            int chosenDigit = -1;

            // Find largest available digit smaller than 
            // limitDigit
            for (int d = limitDigit - 1; d >= 0; d--) {

                if (freq[d] > 0) {

                    // Avoid leading zero
                    if (i == 0 && d == 0) continue;

                    chosenDigit = d;
                    break;
                }
            }

            // Store best break position
            if (chosenDigit != -1) {
                bestIndex = i;
                bestDigit = chosenDigit;
            }

            // Try to match current digit of m
            int matchDigit = m.charAt(i) - '0';

            if (freq[matchDigit] > 0) {
                freq[matchDigit]--;
            } else {
                exactMatch = false;
                break;
            }
        }

        // If exact match exists
        if (exactMatch) {
            return m;
        }

        // Build answer using best break point
        if (bestIndex != -1) {

            String res = "";

            // Prefix from m
            for (int i = 0; i < bestIndex; i++) {
                res += m.charAt(i);
            }

            // Add best smaller digit
            res += (char) ('0' + bestDigit);

            int[] remaining = new int[10];

            // Rebuild frequency
            for (char c : n.toCharArray()) {
                remaining[c - '0']++;
            }

            // Remove prefix digits
            for (int i = 0; i < bestIndex; i++) {
                remaining[m.charAt(i) - '0']--;
            }

            // Remove chosen digit
            remaining[bestDigit]--;

            // Fill remaining digits in descending order
            for (int d = 9; d >= 0; d--) {
                while (remaining[d] > 0) {
                    res += (char) ('0' + d);
                    remaining[d]--;
                }
            }

            return res;
        }

        return "-1";
    }

    public static void main(String[] args) {

        String n = "123";
        String m = "222";

        System.out.println(maxPerm(n, m));
    }
}
Python
def maxPerm(n, m):

    # If n has more digits than m, no valid 
    # permutation is possible
    if len(n) > len(m):
        return "-1"

    # If n has fewer digits than m, return the 
    # largest permutation
    if len(n) < len(m):
        return "".join(sorted(n, reverse=True))

    len_n = len(n)
    freq = [0] * 10

    # Count frequency of digits in n
    for c in n:
        freq[int(c)] += 1

    bestIndex = -1
    bestDigit = -1
    exactMatch = True

    # Try to construct the answer from left to right
    for i in range(len_n):

        limitDigit = int(m[i])
        chosenDigit = -1

        # Find largest available digit smaller than 
        # limitDigit
        for d in range(limitDigit - 1, -1, -1):

            if freq[d] > 0:

                # Avoid leading zero
                if i == 0 and d == 0:
                    continue

                chosenDigit = d
                break

        # Store best break position
        if chosenDigit != -1:
            bestIndex = i
            bestDigit = chosenDigit

        # Try to match current digit of m
        matchDigit = int(m[i])

        if freq[matchDigit] > 0:
            freq[matchDigit] -= 1
        else:
            exactMatch = False
            break

    # If exact match exists
    if exactMatch:
        return m

    # Build answer using best break point
    if bestIndex != -1:

        res = ""

        # Prefix from m
        for i in range(bestIndex):
            res += m[i]

        # Add best smaller digit
        res += str(bestDigit)

        remaining = [0] * 10

        # Rebuild frequency
        for c in n:
            remaining[int(c)] += 1

        # Remove prefix digits
        for i in range(bestIndex):
            remaining[int(m[i])] -= 1

        # Remove chosen digit
        remaining[bestDigit] -= 1

        # Fill remaining digits in descending order
        for d in range(9, -1, -1):
            while remaining[d] > 0:
                res += str(d)
                remaining[d] -= 1

        return res

    return "-1"

if __name__ == "__main__":

    # Sample Input
    n = "123"
    m = "222"

    print(maxPerm(n, m))
C#
using System;

class GFG
{
    static string maxPerm(string n, string m)
    {
        // If n has more digits than m, no valid permutation is possible
        if (n.Length > m.Length)
        {
            return "-1";
        }

        // If n has fewer digits than m, return the largest permutation
        if (n.Length < m.Length)
        {
            char[] arr = n.ToCharArray();
            Array.Sort(arr);

            string res = "";
            for (int i = arr.Length - 1; i >= 0; i--)
            {
                res += arr[i];
            }

            return res;
        }

        int len = n.Length;
        int[] freq = new int[10];

        // Count frequency of digits in n
        for (int i = 0; i < len; i++)
        {
            freq[n[i] - '0']++;
        }

        int bestIndex = -1;
        int bestDigit = -1;
        bool exactMatch = true;

        // Try to construct the answer from left to right
        for (int i = 0; i < len; i++)
        {
            int limitDigit = m[i] - '0';
            int chosenDigit = -1;

            // Find largest available digit smaller than limitDigit
            for (int d = limitDigit - 1; d >= 0; d--)
            {
                if (freq[d] > 0)
                {
                    // Avoid leading zero
                    if (i == 0 && d == 0)
                        continue;

                    chosenDigit = d;
                    break;
                }
            }

            // Store best break position
            if (chosenDigit != -1)
            {
                bestIndex = i;
                bestDigit = chosenDigit;
            }

            // Try to match current digit of m
            int matchDigit = m[i] - '0';

            if (freq[matchDigit] > 0)
            {
                freq[matchDigit]--;
            }
            else
            {
                exactMatch = false;
                break;
            }
        }

        // If exact match exists
        if (exactMatch)
        {
            return m;
        }

        // Build answer using best break point
        if (bestIndex != -1)
        {
            string res = "";

            // Prefix from m
            for (int i = 0; i < bestIndex; i++)
            {
                res += m[i];
            }

            // Add best smaller digit
            res += (char)('0' + bestDigit);

            int[] remaining = new int[10];

            // Rebuild frequency
            for (int i = 0; i < n.Length; i++)
            {
                remaining[n[i] - '0']++;
            }

            // Remove prefix digits
            for (int i = 0; i < bestIndex; i++)
            {
                remaining[m[i] - '0']--;
            }

            // Remove chosen digit
            remaining[bestDigit]--;

            // Fill remaining digits in descending order
            for (int d = 9; d >= 0; d--)
            {
                while (remaining[d] > 0)
                {
                    res += (char)('0' + d);
                    remaining[d]--;
                }
            }

            return res;
        }

        return "-1";
    }

    static void Main()
    {
        string n = "123";
        string m = "222";

        Console.WriteLine(maxPerm(n, m));
    }
}
JavaScript
function maxPerm(n, m) {

    // If n has more digits than m, no valid permutation is possible
    if (n.length > m.length) {
        return "-1";
    }

    // If n has fewer digits than m, return the largest permutation
    if (n.length < m.length) {

        let res = n.split("").sort().reverse().join("");
        return res;
    }

    let len = n.length;
    let freq = Array(10).fill(0);

    // Count frequency of digits in n
    for (let c of n) {
        freq[c.charCodeAt(0) - 48]++;
    }

    let bestIndex = -1;
    let bestDigit = -1;
    let exactMatch = true;

    // Try to construct the answer from left to right
    for (let i = 0; i < len; i++) {

        let limitDigit = m[i].charCodeAt(0) - 48;
        let chosenDigit = -1;

        // Find largest available digit smaller than limitDigit
        for (let d = limitDigit - 1; d >= 0; d--) {

            if (freq[d] > 0) {

                // Avoid leading zero
                if (i === 0 && d === 0) continue;

                chosenDigit = d;
                break;
            }
        }

        // Store best break position
        if (chosenDigit !== -1) {
            bestIndex = i;
            bestDigit = chosenDigit;
        }

        // Try to match current digit of m
        let matchDigit = m[i].charCodeAt(0) - 48;

        if (freq[matchDigit] > 0) {
            freq[matchDigit]--;
        } else {
            exactMatch = false;
            break;
        }
    }

    // If exact match exists
    if (exactMatch) {
        return m;
    }

    // Build answer using best break point
    if (bestIndex !== -1) {

        let res = "";

        // Prefix from m
        for (let i = 0; i < bestIndex; i++) {
            res += m[i];
        }

        // Add best smaller digit
        res += String(bestDigit);

        let remaining = Array(10).fill(0);

        // Rebuild frequency
        for (let c of n) {
            remaining[c.charCodeAt(0) - 48]++;
        }

        // Remove prefix digits
        for (let i = 0; i < bestIndex; i++) {
            remaining[m[i].charCodeAt(0) - 48]--;
        }

        // Remove chosen digit
        remaining[bestDigit]--;

        // Fill remaining digits in descending order
        for (let d = 9; d >= 0; d--) {
            while (remaining[d] > 0) {
                res += String(d);
                remaining[d]--;
            }
        }

        return res;
    }

    return "-1";
}

// Driver code
let n = "123";
let m = "222";
console.log(maxPerm(n, m));

Output
213
Comment