每日一题——最接近目标价格的甜点成本

130 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 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.length
  • m == toppingCosts.length
  • 1 <= n, m <= 10
  • 1 <= baseCosts[i], toppingCosts[i] <= 104
  • 1 <= 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]);
    }
}