Hard
题目描述
给定一个整数数组 cost 和一个整数 target,在满足以下规则的条件下,返回你可以绘制的最大整数:
- 绘制数字
(i + 1)的成本由cost[i]给出(下标从 0 开始) - 使用的总成本必须等于
target - 整数不能包含数字 0
由于答案可能很大,请以字符串形式返回。如果在给定条件下无法绘制任何整数,则返回 “0”。
示例 1:
输入:cost = [4,3,2,5,6,7,2,5,5], target = 9
输出:"7772"
解释:绘制数字 '7' 的成本是 2,数字 '2' 的成本是 3。那么 cost("7772") = 2*3+ 3*1 = 9。你也可以绘制 "977",但 "7772" 是更大的数字。
示例 2:
输入:cost = [7,6,5,5,5,6,8,7,8], target = 12
输出:"85"
解释:绘制数字 '8' 的成本是 7,数字 '5' 的成本是 5。那么 cost("85") = 7 + 5 = 12。
示例 3:
输入:cost = [2,4,6,2,4,6,4,4,4], target = 5
输出:"0"
解释:不可能绘制任何总成本等于 target 的整数。
约束条件:
cost.length == 91 <= cost[i], target <= 5000
解题思路
这道题需要分两步解决:
第一步:动态规划求最大位数
使用 DP 确定能否达到目标成本以及最大位数。定义 dp[i] 为成本为 i 时能构成的最大位数。状态转移方程为:
dp[i] = max(dp[i], dp[i - cost[j]] + 1) // 对所有数字 j+1
第二步:贪心构造最大数字 在确定了最大位数后,需要构造字典序最大的数字。关键思路是:
- 从最大的数字9开始尝试
- 对于每个数字,检查使用它后剩余成本是否还能构成足够的位数
- 优先选择较大的数字,这样可以保证字典序最大
例如,如果目标成本是9,可以构成3位数,那么优先选择成本最小的数字来填充更多位数,但在前面的位置优先选择更大的数字。
时间复杂度主要来自两部分:DP 计算 O(target × 9) 和构造结果 O(最大位数)。
推荐解法: 动态规划 + 贪心构造,这是最直接有效的方法。
代码实现
class Solution {
public:
string largestNumber(vector<int>& cost, int target) {
vector<int> dp(target + 1, -1);
dp[0] = 0;
for (int i = 1; i <= target; i++) {
for (int j = 0; j < 9; j++) {
if (i >= cost[j] && dp[i - cost[j]] != -1) {
dp[i] = max(dp[i], dp[i - cost[j]] + 1);
}
}
}
if (dp[target] == -1) return "0";
string result = "";
int remain = target;
for (int digits = dp[target]; digits > 0; digits--) {
for (int digit = 9; digit >= 1; digit--) {
int c = cost[digit - 1];
if (remain >= c && dp[remain - c] == digits - 1) {
result += char('0' + digit);
remain -= c;
break;
}
}
}
return result;
}
};
class Solution:
def largestNumber(self, cost: List[int], target: int) -> str:
dp = [-1] * (target + 1)
dp[0] = 0
for i in range(1, target + 1):
for j in range(9):
if i >= cost[j] and dp[i - cost[j]] != -1:
dp[i] = max(dp[i], dp[i - cost[j]] + 1)
if dp[target] == -1:
return "0"
result = ""
remain = target
for digits in range(dp[target], 0, -1):
for digit in range(9, 0, -1):
c = cost[digit - 1]
if remain >= c and dp[remain - c] == digits - 1:
result += str(digit)
remain -= c
break
return result
public class Solution {
public string LargestNumber(int[] cost, int target) {
int[] dp = new int[target + 1];
Array.Fill(dp, -1);
dp[0] = 0;
for (int i = 1; i <= target; i++) {
for (int j = 0; j < 9; j++) {
if (i >= cost[j] && dp[i - cost[j]] != -1) {
dp[i] = Math.Max(dp[i], dp[i - cost[j]] + 1);
}
}
}
if (dp[target] == -1) return "0";
StringBuilder result = new StringBuilder();
int remain = target;
for (int digits = dp[target]; digits > 0; digits--) {
for (int digit = 9; digit >= 1; digit--) {
int c = cost[digit - 1];
if (remain >= c && dp[remain - c] == digits - 1) {
result.Append(digit);
remain -= c;
break;
}
}
}
return result.ToString();
}
}
var largestNumber = function(cost, target) {
const dp = new Array(target + 1).fill(-1);
dp[0] = 0;
for (let i = 1; i <= target; i++) {
for (let j = 0; j < 9; j++) {
if (i >= cost[j] && dp[i - cost[j]] !== -1) {
dp[i] = Math.max(dp[i], dp[i - cost[j]] + 1);
}
}
}
if (dp[target]
复杂度分析
| 复杂度类型 | 复杂度 |
|---|---|
| 时间复杂度 | O(target × 9 + 最大位数 × 9) = O(target) |
| 空间复杂度 | O(target) |