题:
思:
最终的数位成本和必须恰好等于target
换算为背包问题(拿了以后还可以再拿)
数位1到9 对应9个物品,cost[0到8] 对应9个物品的重量;物品本身代表了自己的价值:
要在尽可能的多拿物品(多拿数位),然后对结果进行排序,得到最大的价值
所以可以把每个物品的价值都理解为1,因为每个物品的价值是等价的
dp[i]表示重量为i的时候,最大的数位和(String类型)
对于每一个物品(数位),我们可以选择拿或者不拿,如果拿的话,则把它插入到头部,因为循环越往后,数位越大,这样就无需给已经获得的数位排序了
每一个物品的重量(cost)为c,价值为1,因此数位和的长度直接代表了价值,无需在dp里存放价值
每一个物品(数位)的值恰好为循环的次数k
因此dp[i] = max(dp[i],“k”+dp[i-c]) 如果dp[i-c]为0(字符串里是"“代表空),则"k”+dp[i-c]也为"" ,当二者长度相同时(这里是为了满足恰好等于target)
如果二者长度不同,则dp[i] = 二者中长度长的那个
不用避免过去的自己被先更新,且同一个数位可以重复使用多次,因此内部循环应该从小往大遍历
最重要的一点:一个数字可以重复多次被拿,所以dp[i-c]应该循环数次,从小往大遍历可以直接解决这个问题(骚操作!)
码:
public static String largestNumber(int[] cost, int target) {
String[] dp = new String[target + 1];
for (int i = 0; i < dp.length; i++) {
dp[i]="";
}
// 固定cost的大小为9
for (int a = 1; a <= 9; a++) {
int c = cost[a - 1]; // 第a个数位的成本为cost[a-1]
// 如果当前数位的成本大于target,就别考虑它了
if(c > target){
continue;
}
String k = "" + a; // 每一个物品(数位)的值恰好为循环的次数k
// 每次应该先对当前物品,确定一下重量为多少的时候,可以拿它。
if (dp[c].length() == 0) {
dp[c] = k;
}else if(dp[c].length() == 1){
dp[c] = dp[c].compareTo(k)>0?dp[c]:k;
}
for (int i = c; i <= target; i++) {
if (dp[i - c] == "") {
dp[i] = dp[i];
} else {
if (dp[i].length() == (k + dp[i - c]).length()) {
// 比较字符串
if (dp[i].compareTo(k + dp[i - c]) < 0) {
dp[i] = k + dp[i - c];
}
} else if (dp[i].length() > (k + dp[i - c]).length()) {
dp[i] = dp[i];
} else {
dp[i] = k + dp[i - c];
}
}
}
}
if(dp[target]=="")
return "0";
return dp[target];
}