题目链接
题目描述
注意
- 1 <= n, m <= 10
- 必须选择 一种 冰激凌基料
- 可以添加 一种或多种 配料,也可以不添加任何配料
- 每种类型的配料 最多两份
- 返回最接近 target 的甜点成本。如果有多种方案,返回 成本相对较低 的一种
解答思路
- 由题意得,必须选择一种基料,在任意一个甜点搭配中,基料都有且仅有一个,所以遍历所有的基料,其作为初始成本,再根据初始成本找到其对应的更接近目标价格的甜点成本
- 采用深度优先遍历基于基料找到更接近甜点成本的配料搭配,又因为可以添加一种或多种配料,也可以不添加任何配料,所以进行深度优先遍历时,对于每种配料,有3种情况:添加0份、1份、2份该配料,对这三种情况都进行深度优先遍历,最终对这三种情况的成本进行判断找到更接近目标价格的甜点成本
- 本题只需要找到最接近目标价格的甜点成本,所以在深度优先遍历中,是可以进行剪枝的,例如如果某次搭配的成本等于目标价格,则其他情况都不需要讨论了,直接返回目标价格即可;还有可以对配料成本进行排序,对其从小到大进行遍历,如果某次搭配的成本大于目标价格且相较于之前的最优搭配并不更接近目标价格,则该情况不需要再进行深度优先遍历,因为之后的成本只会更高,更远离目标价格, 不可能满足题意
代码
方法一:
class Solution {
public int closestCost(int[] baseCosts, int[] toppingCosts, int target) {
Arrays.sort(baseCosts);
Arrays.sort(toppingCosts);
int res = Integer.MAX_VALUE;
// 必须选择一份基料,根据基料深度优先遍历找到更接近目标价格的配料搭配
for (int i = 0; i < baseCosts.length; i++) {
res = findCloser(res, dfs(toppingCosts, target, baseCosts[i], 0), target);
// 如果已经是甜点成本,则直接返回
if (res == target) return res;
}
return res;
}
// 深度优先遍历找到所有的配料情况(注意剪枝)
public int dfs(int[] toppingCosts, int target, int sum, int idx) {
int res = sum;
// 如果已经是甜点成本或配料情况已经全部考虑完,则直接返回
if (sum == target || idx >= toppingCosts.length) return res;
// 加入0份idx配料
// 此时成本已经多于目标价格且后续成本还会增加,不需要再进行dfs
if (sum > target && Math.abs(target - sum) > Math.abs(target - res)) return res;
res = findCloser(res, dfs(toppingCosts, target, sum, idx + 1), target);
// 加入1份idx配料
sum += toppingCosts[idx];
if (sum > target && Math.abs(target - sum) > Math.abs(target - res)) return res;
res = findCloser(res, dfs(toppingCosts, target, sum, idx + 1), target);
// 加入2份idx配料
sum += toppingCosts[idx];
if (sum > target && Math.abs(target - sum) > Math.abs(target - res)) return res;
res = findCloser(res, dfs(toppingCosts, target, sum, idx + 1), target);
return res;
}
// 找到更接近目标价格的甜点成本
public int findCloser(int sum1, int sum2, int target) {
if (Math.abs(target - sum1) > Math.abs(target - sum2)) {
return sum2;
} else if (Math.abs(target - sum1) < Math.abs(target - sum2)) {
return sum1;
} else {
return Math.min(sum1, sum2);
}
}
}
关键点
- 深度优先遍历的思想
- 讨论剪枝的情况