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".
Table of Content
[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.
#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;
}
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));
}
}
# 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))
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));
}
}
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"
#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;
}
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));
}
}
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))
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));
}
}
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