开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第14天,点击查看活动详情
最接近目标价格的甜点成本
你打算做甜点,现在需要购买配料。目前共有 n 种冰激凌基料和 m 种配料可供选购。而制作甜点需要遵循以下几条规则:
- 必须选择 一种 冰激凌基料。
- 可以添加 一种或多种 配料,也可以不添加任何配料。
- 每种类型的配料 最多两份 。
给你以下三个输入:
baseCosts,一个长度为n的整数数组,其中每个baseCosts[i]表示第i种冰激凌基料的价格。toppingCosts,一个长度为m的整数数组,其中每个toppingCosts[i]表示 一份 第i种冰激凌配料的价格。target,一个整数,表示你制作甜点的目标价格。
你希望自己做的甜点总成本尽可能接近目标价格 target 。
返回最接近 **target 的甜点成本。如果有多种方案,返回 成本相对较低 的一种。
示例 1:
输入: baseCosts = [1,7], toppingCosts = [3,4], target = 10
输出: 10
解释: 考虑下面的方案组合(所有下标均从 0 开始):
- 选择 1 号基料:成本 7
- 选择 1 份 0 号配料:成本 1 x 3 = 3
- 选择 0 份 1 号配料:成本 0 x 4 = 0
总成本:7 + 3 + 0 = 10 。
提示:
n == baseCosts.lengthm == toppingCosts.length1 <= n, m <= 101 <= baseCosts[i], toppingCosts[i] <= 1041 <= target <= 104
思路
可以使用回溯的方法解决该问题,对于每一种基料来说,可以遍历配料的所有情况来计算成本,对于某一种配料来说,包括三种情况:未添加配料,添加一次配料,添加两次配料。对于每个配料都需要尝试以上三种情况,以此即可完成所有情况的遍历。
该题的难点主要在于终止条件的判断,只要想清楚,其实也不是很难,考虑清楚每种情况是不是该停止搜索即可。
回溯的终止条件:
- 若当前成本与预期的差值大于已有最优方案的差值,则停止搜索,因为之后搜索的差值只会越来越大,偏离最优方案;
- 若当前成本与预期的差值小于已有最优方案的差值时,可直接更新当前最优成本;
- 若当前成本与预期的差值等于已有最优方案的差值时,可将该最优成本调整为较小成本;
- 若当前已遍历所有配料的情况,则停止。
题目要求一定要有一个基料,故初始化时要先选择一个最小的成本。
题解
class Solution {
private int[] baseCosts;
private int[] toppingCosts;
private int target;
private int ans = Integer.MAX_VALUE;
public int closestCost(int[] baseCosts, int[] toppingCosts, int target) {
this.baseCosts = baseCosts;
this.toppingCosts = toppingCosts;
this.target = target;
for(int base: baseCosts) {
ans = Math.min(ans, base);
}
for(int base: baseCosts) {
dfs(0, base);
}
return ans;
}
private void dfs(int index, int sum) {
if (Math.abs(ans - target) < sum - target) {
return;
} else if (Math.abs(ans - target) >= Math.abs(sum - target)) {
if (Math.abs(ans - target) > Math.abs(sum - target)) {
ans = sum;
} else {
ans = Math.min(ans, sum);
}
}
if(index == toppingCosts.length) {
return;
}
dfs(index + 1, sum);
dfs(index + 1, sum + toppingCosts[index]);
dfs(index + 1, sum + 2 * toppingCosts[index]);
}
}