You are given a string of digits num
and an integer array change
of length 10, where change[i]
indicates the digit you can mutate digit i
into. You can choose at most one contiguous substring of num
and mutate every digit x
within this substring to change[x]
. Each digit in the chosen substring must be mutated (no skipping). Your goal is to return the largest possible number obtainable as a string after performing at most one such mutation.
change
.At first glance, one might consider brute-forcing all possible substrings and checking the result after mutating each. However, with a string of length up to 105, this would be too slow.
Instead, let's think about when it's beneficial to mutate a digit. If change[digit]
is greater than the original digit, mutating increases the value. If it's less, mutating decreases the value and should be avoided. If it's equal, mutating has no effect.
The best strategy is to start mutating at the first position where change[digit] > digit
and continue mutating as long as change[digit] ≥ digit
. We must stop as soon as change[digit] < digit
to avoid decreasing the number.
This greedy approach ensures we create the largest possible number in a single pass, avoiding unnecessary mutations.
d
where change[d] > d
. This is where we should start mutating.change[d] ≥ d
for each digit in the substring.change[d] < d
, stop mutating. From here onward, keep the original digits.This approach is greedy and only mutates when it increases or keeps the value, and stops as soon as it would decrease the value. We only ever mutate one contiguous substring, as the problem requires.
Consider num = "132"
and change = [9,8,5,0,3,6,4,2,6,8]
.
change[1] = 8
, which is greater than 1. Start mutating here.change[3] = 0
, which is less than 3. Stop mutating before this digit."832"
.If we continued mutating after the first digit, the number would decrease, which is not optimal.
The greedy approach is both time and space efficient.
By analyzing when mutating digits increases the value, we use a greedy, one-pass strategy to find the largest number. We start mutating at the first opportunity and stop as soon as mutating would decrease the number. This ensures correctness and efficiency, making the solution both elegant and optimal.
class Solution:
def maximumNumber(self, num: str, change: List[int]) -> str:
num_list = list(num)
n = len(num)
started = False
for i in range(n):
d = int(num_list[i])
if not started:
if change[d] > d:
started = True
num_list[i] = str(change[d])
else:
if change[d] >= d:
num_list[i] = str(change[d])
else:
break
return ''.join(num_list)
class Solution {
public:
string maximumNumber(string num, vector<int>& change) {
bool started = false;
int n = num.size();
for (int i = 0; i < n; ++i) {
int d = num[i] - '0';
if (!started) {
if (change[d] > d) {
started = true;
num[i] = change[d] + '0';
}
} else {
if (change[d] >= d) {
num[i] = change[d] + '0';
} else {
break;
}
}
}
return num;
}
};
class Solution {
public String maximumNumber(String num, int[] change) {
char[] arr = num.toCharArray();
boolean started = false;
for (int i = 0; i < arr.length; ++i) {
int d = arr[i] - '0';
if (!started) {
if (change[d] > d) {
started = true;
arr[i] = (char)(change[d] + '0');
}
} else {
if (change[d] >= d) {
arr[i] = (char)(change[d] + '0');
} else {
break;
}
}
}
return new String(arr);
}
}
var maximumNumber = function(num, change) {
let arr = num.split('');
let started = false;
for (let i = 0; i < arr.length; ++i) {
let d = parseInt(arr[i]);
if (!started) {
if (change[d] > d) {
started = true;
arr[i] = change[d].toString();
}
} else {
if (change[d] >= d) {
arr[i] = change[d].toString();
} else {
break;
}
}
}
return arr.join('');
};