Medium
题目描述
给你一个字符串 num,表示一个大整数。另给你一个长度为 10 的整数数组 change,该数组将每个数字 0-9 映射到另一个数字。更正式地说,数字 d 映射到数字 change[d]。
你可以选择 变更 num 的一个子字符串。要变更子字符串,将子字符串中的每个数字 num[i] 替换为它在 change 中映射的数字(即,将 num[i] 替换为 change[num[i]])。
返回一个字符串,表示变更(或不变更)一个子字符串后能得到的最大整数。
子字符串 是字符串中的一个连续字符序列。
示例 1:
输入: num = "132", change = [9,8,5,0,3,6,4,2,6,8]
输出: "832"
解释: 替换子字符串 "1":
- 1 映射到 change[1] = 8
因此,"132" 变为 "832"。
"832" 是能创建的最大数字,所以返回它。
示例 2:
输入: num = "021", change = [9,4,3,5,7,2,1,9,0,6]
输出: "934"
解释: 替换子字符串 "021":
- 0 映射到 change[0] = 9
- 2 映射到 change[2] = 3
- 1 映射到 change[1] = 4
因此,"021" 变为 "934"。
"934" 是能创建的最大数字,所以返回它。
示例 3:
输入: num = "5", change = [1,4,7,5,3,2,5,6,9,4]
输出: "5"
解释: "5" 已经是能创建的最大数字,所以返回它。
约束条件:
- 1 <= num.length <= 10^5
- num 只由数字 0-9 组成
- change.length == 10
- 0 <= change[d] <= 9
解题思路
这道题需要使用贪心策略来解决。核心思路是找到一个连续的子字符串进行变更,使得整个数字最大。
贪心策略分析:
- 从左到右扫描:为了使数字最大,我们应该尽可能让高位变大,所以从左到右扫描数字
- 开始变更的条件:当遇到第一个能够变得更大的数字时(即
change[digit] > digit),开始变更 - 停止变更的条件:一旦开始变更,就要连续变更直到遇到会变小的数字(即
change[digit] < digit)为止
算法步骤:
- 遍历字符串,寻找第一个能变大的数字位置
- 从该位置开始连续变更,直到遇到会变小的数字或字符串结束
- 如果某个数字变更后不变(
change[digit] == digit),继续变更以保持子字符串的连续性
这种贪心策略是最优的,因为:
- 越靠前的位置对数字大小影响越大
- 一旦开始变更就要保持连续性,不能跳过中间的数字
代码实现
class Solution {
public:
string maximumNumber(string num, vector<int>& change) {
int n = num.length();
bool started = false;
for (int i = 0; i < n; i++) {
int digit = num[i] - '0';
int newDigit = change[digit];
if (!started) {
if (newDigit > digit) {
num[i] = '0' + newDigit;
started = true;
}
} else {
if (newDigit < digit) {
break;
}
num[i] = '0' + newDigit;
}
}
return num;
}
};
class Solution:
def maximumNumber(self, num: str, change: List[int]) -> str:
num = list(num)
n = len(num)
started = False
for i in range(n):
digit = int(num[i])
new_digit = change[digit]
if not started:
if new_digit > digit:
num[i] = str(new_digit)
started = True
else:
if new_digit < digit:
break
num[i] = str(new_digit)
return ''.join(num)
public class Solution {
public string MaximumNumber(string num, int[] change) {
char[] arr = num.ToCharArray();
int n = arr.Length;
bool started = false;
for (int i = 0; i < n; i++) {
int digit = arr[i] - '0';
int newDigit = change[digit];
if (!started) {
if (newDigit > digit) {
arr[i] = (char)('0' + newDigit);
started = true;
}
} else {
if (newDigit < digit) {
break;
}
arr[i] = (char)('0' + newDigit);
}
}
return new string(arr);
}
}
var maximumNumber = function(num, change) {
let arr = num.split('');
let n = arr.length;
let started = false;
for (let i = 0; i < n; i++) {
let digit = parseInt(arr[i]);
let newDigit = change[digit];
if (!started) {
if (newDigit > digit) {
arr[i] = newDigit.toString();
started = true;
}
} else {
if (newDigit < digit) {
break;
}
arr[i] = newDigit.toString();
}
}
return arr.join('');
};
复杂度分析
| 复杂度类型 | 值 | 说明 |
|---|---|---|
| 时间复杂度 | O(n) | 需要遍历整个字符串一次,n为字符串长度 |
| 空间复杂度 | O(1) 或 O(n) | C++直接修改原字符串为O(1),其他语言需要额外空间存储结果为O(n) |