[LeetCode] 638. Shopping Offers

In LeetCode Store, there are n items to sell. Each item has a price. However, there are some special offers, and a special offer consists of one or more different kinds of items with a sale price.

You are given an integer array price where price[i] is the price of the ith item, and an integer array needs where needs[i] is the number of pieces of the ith item you want to buy.

You are also given an array special where special[i] is of size n + 1 where special[i][j] is the number of pieces of the jth item in the ith offer and special[i][n] (i.e., the last integer in the array) is the price of the ith offer.

Return the lowest price you have to pay for exactly certain items as given, where you could make optimal use of the special offers. You are not allowed to buy more items than you want, even if that would lower the overall price. You could use any of the special offers as many times as you want.

Example 1:

Input: price = [2,5], special = [[3,0,5],[1,2,10]], needs = [3,2]
Output: 14
Explanation: There are two kinds of items, A and B. Their prices are $2 and $5 respectively. 
In special offer 1, you can pay $5 for 3A and 0B
In special offer 2, you can pay $10 for 1A and 2B. 
You need to buy 3A and 2B, so you may pay $10 for 1A and 2B (special offer #2), and $4 for 2A.

Example 2:

Input: price = [2,3,4], special = [[1,1,0,4],[2,2,1,9]], needs = [1,2,1]
Output: 11
Explanation: The price of A is $2, and $3 for B, $4 for C. 
You may pay $4 for 1A and 1B, and $9 for 2A ,2B and 1C. 
You need to buy 1A ,2B and 1C, so you may pay $4 for 1A and 1B (special offer #1), and $3 for 1B, $4 for 1C. 
You cannot add more items, though only $9 for 2A ,2B and 1C.

Constraints:

  • n == price.length
  • n == needs.length
  • 1 <= n <= 6
  • 0 <= price[i] <= 10
  • 0 <= needs[i] <= 10
  • 1 <= special.length <= 100
  • special[i].length == n + 1
  • 0 <= special[i][j] <= 50

大礼包。

在 LeetCode 商店中, 有 n 件在售的物品。每件物品都有对应的价格。然而,也有一些大礼包,每个大礼包以优惠的价格捆绑销售一组物品。

给你一个整数数组 price 表示物品价格,其中 price[i] 是第 i 件物品的价格。另有一个整数数组 needs 表示购物清单,其中 needs[i] 是需要购买第 i 件物品的数量。

还有一个数组 special 表示大礼包,special[i] 的长度为 n + 1 ,其中 special[i][j] 表示第 i 个大礼包中内含第 j 件物品的数量,且 special[i][n] (也就是数组中的最后一个整数)为第 i 个大礼包的价格。

返回 确切 满足购物清单所需花费的最低价格,你可以充分利用大礼包的优惠活动。你不能购买超出购物清单指定数量的物品,即使那样会降低整体价格。任意大礼包可无限次购买。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shopping-offers
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路是 backtracking。我们需要买一些商品,每件商品的个数我们用一个 list 记录好了。我们也有一些 offer,会有一些特别的价钱。我们的目的是看看能否买到所有的东西并且使得总价最低。注意这里不能为了得到更优惠的价钱而多买任何东西。

使用 backtracking 是因为我们不知道走到哪一步,就不能再使用某个 offer 了。当我们不能使用某个 offer 的时候,我们要往回退一步接着试探别的 offer。这里的 base case 是所有需要的东西都按原来的单价购买。

时间O(n)

空间O(n)

Java实现

 1 class Solution {
 2     int minPrice;
 3     
 4     private int directBuy(List<Integer> price, List<Integer> needs) {
 5         int sum = 0;
 6         int n = price.size();
 7         for (int i = 0; i < n; i++) {
 8             sum += price.get(i) * needs.get(i);
 9         }
10         return sum;
11     }
12 
13     public int shoppingOffers(List<Integer> price, List<List<Integer>> special, List<Integer> needs) {
14         minPrice = directBuy(price, needs);
15         helper(price, special, needs, 0, 0);
16         return minPrice;
17     }
18 
19     // 检查是否能使用当前的special price
20     private boolean canUse(List<Integer> offer, List<Integer> needs) {
21         int n = needs.size();
22         for (int i = 0; i < n; i++) {
23             if (needs.get(i) < offer.get(i)) {
24                 return false;
25             }
26         }
27         return true;
28     }
29 
30     private void helper(List<Integer> price, List<List<Integer>> special, List<Integer> needs, int index, int used) {
31         // base case
32         if (used >= minPrice) {
33             return;
34         }
35 
36         // 如果遍历完special price之后还没有买完需要的东西,则按原来的单价购买
37         if (index == special.size()) {
38             used += directBuy(price, needs);
39             // 如果购买价可以被更新则更新
40             if (used < minPrice) {
41                 minPrice = used;
42             }
43             return;
44         }
45 
46         List<Integer> offer = special.get(index);
47         if (canUse(offer, needs)) {
48             int n = needs.size();
49             List<Integer> updatedNeeds = new ArrayList<>();
50             for (int i = 0; i < n; i++) {
51                 updatedNeeds.add(needs.get(i) - offer.get(i));
52             }
53             helper(price, special, updatedNeeds, index, used + offer.get(n));
54         }
55         helper(price, special, needs, index + 1, used);
56     }
57 }

LeetCode 题目总结

原文地址:https://www.cnblogs.com/cnoodle/p/15473589.html