持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第26天,点击查看活动详情
给你一个整数数组 cost 和一个整数 target 。请你返回满足如下规则可以得到的 最大 整数:
- 给当前结果添加一个数位(
i + 1)的成本为cost[i](cost数组下标从 0 开始)。 - 总成本必须恰好等于
target。 - 添加的数位中没有数字 0 。
由于答案可能会很大,请你以字符串形式返回。
如果按照上述要求无法得到任何整数,请你返回 "0" 。
示例 1:
输入:cost = [4,3,2,5,6,7,2,5,5], target = 9
输出:"7772"
解释:添加数位 '7' 的成本为 2 ,添加数位 '2' 的成本为 3 。所以 "7772" 的代价为 2*3+ 3*1 = 9 。 "977" 也是满足要求的数字,但 "7772" 是较大的数字。
数字 成本
1 -> 4
2 -> 3
3 -> 2
4 -> 5
5 -> 6
6 -> 7
7 -> 2
8 -> 5
9 -> 5
示例 2:
输入:cost = [7,6,5,5,5,6,8,7,8], target = 12
输出:"85"
解释:添加数位 '8' 的成本是 7 ,添加数位 '5' 的成本是 5 。"85" 的成本为 7 + 5 = 12 。
示例 3:
输入:cost = [2,4,6,2,4,6,4,4,4], target = 5
输出:"0"
解释:总成本是 target 的条件下,无法生成任何整数。
示例 4:
输入:cost = [6,10,15,40,40,40,40,40,40], target = 47
输出:"32211"
动态规划
若两个整数位数不同,位数更多的整数必然大于位数小的整数。因此我们需要先计算出可以得到的整数的最大位数。
该问题可以看作是恰好装满背包容量为 ,物品重量为 ,价值为 的完全背包问题。
对于该问题,定义二维数组 ,其中 表示使用前 个数位且花费总成本恰好为 时的最大位数,若花费总成本无法为 ,则规定其为 。特别地, 为不选任何数位的状态,因此除了 为 ,其余 全为 。
即为可以得到的整数的最大位数,若其小于 则说明我们无法得到满足要求的整数,返回 。否则,我们需要生成一个整数,其位数为 且数值最大。
为了生成该整数,我们可以用一个额外的二维数组 ,在状态转移时记录转移来源。这样我们可以从最终状态 顺着 不断倒退,直至达到起始状态 。在倒退状态时,若转移来源是 则说明我们选取了第 个数位。
注意我们并没有记录转移来源是 还是 ,这是因为若 的值为 ,则必定从 转移过来,否则必定从 转移过来。
此外,由于我们是从最大的数位向最小的数位倒退,为使生成的整数尽可能地大,对于当前数位应尽可能多地选取,所以当 与 相等时,我们选择从后者转移过来。
这样我们就得到了每个数位的选择次数,为使生成的整数尽可能地大,我们应按照从大到小的顺序填入各个数位。由于该顺序与倒退状态的顺序一致,我们可以在倒退状态时,将当前数位直接加入生成的整数末尾。
代码实现时, 可以用一个非常小的负数表示,保证转移时对于值为 的状态,其 之后仍然为负数。
var largestNumber = function(cost, target) {
const dp = new Array(10).fill(0).map(() => new Array(target + 1).fill(-Number.MAX_VALUE));
const from = new Array(10).fill(0).map(() => new Array(target + 1).fill(0));
dp[0][0] = 0;
for (let i = 0; i < 9; ++i) {
const c = cost[i];
for (let j = 0; j <= target; ++j) {
if (j < c) {
dp[i + 1][j] = dp[i][j];
from[i + 1][j] = j;
} else {
if (dp[i][j] > dp[i + 1][j - c] + 1) {
dp[i + 1][j] = dp[i][j];
from[i + 1][j] = j;
} else {
dp[i + 1][j] = dp[i + 1][j - c] + 1;
from[i + 1][j] = j - c;
}
}
}
}
if (dp[9][target] < 0) {
return "0";
}
const sb = [];
let i = 9, j = target;
while (i > 0) {
if (j === from[i][j]) {
--i;
} else {
sb.push(i);
j = from[i][j];
}
}
return sb.join('');
};