题目描述
思路:暴力DFS
https://leetcode-cn.com/problems/shopping-offers/solution/tong-ge-lai-shua-ti-la-yi-ti-liang-jie-b-2ccb/
首先,观察本题给定的数据范围非常小,我们可以先尝试使用暴力求解,使用暴力的突破口是我们需要的物品数量,每当递归一次,我们就把需要的物品数量减少一次,当然,我们的每一次递归中有两个分支,即不使用礼包和使用一个礼包。
请看代码,加了详细注释:
class Solution {int n;public int shoppingOffers(List<Integer> price,List<List<Integer>> special,List<Integer> needs) {this.n = price.size();return dfs(price, special, needs);}private int dfs(List<Integer> price,List<List<Integer>> special,List<Integer> needs) {// 不使用大礼包的情况下int ans = 0;for (int i = 0; i < n; i++) {ans += needs.get(i) * price.get(i);}// 使用大礼包的情况下for (List<Integer> s : special) {// 大礼包可以购买无限次// 这里相当于深拷贝一个新的List出来,所以,下面不用恢复状态了List<Integer> curr = new ArrayList<>(needs);boolean flag = false;for (int i = 0; i < n; i++) {// 判断是否超出数量限制if (curr.get(i) - s.get(i) < 0) {flag = true;break;}curr.set(i, curr.get(i) - s.get(i));}// 未超出数量限制if (!flag) {// 选定这个礼包,并继续递归ans = Math.min(ans, s.get(n) + dfs(price, special, curr));}}return ans;}}
思路二:记忆化搜索
其实,仔细分析上面的暴力解法,对于每一种需求数量,会出现重复计算,所以,我们可以加上记忆化的逻辑,遇到同一种状态,可以直接返回,提高效率。
class Solution {int n;public int shoppingOffers(List<Integer> price,List<List<Integer>> special,List<Integer> needs) {this.n = price.size();Map<List<Integer>, Integer> cache = new HashMap<>();return dfs(price, special, needs, cache);}private int dfs(List<Integer> price,List<List<Integer>> special,List<Integer> needs,Map<List<Integer>, Integer> cache) {if (cache.containsKey(needs)) {return cache.get(needs);}// 不使用大礼包的情况下int ans = 0;for (int i = 0; i < n; i++) {ans += needs.get(i) * price.get(i);}// 使用大礼包的情况下for (List<Integer> s : special) {// 大礼包可以购买无限次List<Integer> curr = new ArrayList<>(needs);boolean flag = false;for (int i = 0; i < n; i++) {// 判断是否超出数量限制if (curr.get(i) - s.get(i) < 0) {flag = true;break;}curr.set(i, curr.get(i) - s.get(i));}// 未超出数量限制if (!flag) {ans = Math.min(ans, s.get(n) + dfs(price, special, curr, cache));}}cache.put(needs, ans);return ans;}}
反思
我是废物


