大礼包
难度:
标签:
题目描述
代码结果
运行时间: 40 ms, 内存: 16.9 MB
// Java Stream Solution
// 题目思路:
// 1. 与Java方法类似,使用stream和lambda表达式来简化代码逻辑。
// 2. 使用stream API遍历special大礼包,并计算所有可能的最低价格。
import java.util.*;
public class Solution {
public int shoppingOffers(List<Integer> price, List<List<Integer>> special, List<Integer> needs) {
return dfs(price, special, needs);
}
private int dfs(List<Integer> price, List<List<Integer>> special, List<Integer> needs) {
int minPrice = needs.stream().mapToInt(i -> price.get(i) * needs.get(i)).sum();
for (List<Integer> offer : special) {
List<Integer> clone = new ArrayList<>(needs);
boolean valid = true;
for (int i = 0; i < needs.size(); i++) {
int diff = clone.get(i) - offer.get(i);
if (diff < 0) {
valid = false;
break;
}
clone.set(i, diff);
}
if (valid) {
minPrice = Math.min(minPrice, offer.get(needs.size()) + dfs(price, special, clone));
}
}
return minPrice;
}
}
解释
方法:
此题解使用回溯法来寻找最低花费的购买方案。首先,它过滤出那些实际可以节省费用的特殊包裹(即大礼包的总价值小于单独购买包含商品的价格)。然后,从每一个有效的大礼包开始递归尝试,同时更新剩余需要的物品数量和总花费。如果当前尝试的总价已经超过已知的最低价格,则提前结束该路径的探索。此外,如果不能再使用当前大礼包,它会尝试单独购买剩余的每种商品,并更新总花费。
时间复杂度:
O(2^m * n) 其中 m 是有效大礼包的数量,n 是物品种类的数量
空间复杂度:
O(m + n) 其中 m 是大礼包的数量,n 是物品种类的数量
代码细节讲解
🦆
在过滤大礼包时,为什么要检查`sum(sp[i] * price[i] for i in range(n)) > sp[-1]`?这个条件是怎样帮助确保节省成本的?
▷🦆
回溯函数中的`special_idx`参数具体是用来做什么的?如何影响递归过程中大礼包的选择?
▷🦆
为什么在尝试每个大礼包时需要创建`updated_remainder`的副本而不是直接修改`remainder`?
▷🦆
题解中提到如果当前花费已经不是最优则停止搜索,这种策略是如何帮助优化算法性能的?
▷