Leetcode——638. Shopping Offers

题目原址

https://leetcode.com/problems/shopping-offers/description/

题目描述

Example 1:

Input: [2,5], [[3,0,5],[1,2,10]], [3,2]
Output: 14
Explanation:
There are two kinds of items, A and B. Their prices are 2and 2 a n d 5 respectively.
In special offer 1, you can pay 5for3Aand0BInspecialoffer2,youcanpay 5 f o r 3 A a n d 0 B I n s p e c i a l o f f e r 2 , y o u c a n p a y 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 10 for 1A and 2B (special offer #2), and 4 for 2A.

Example 2:

Input: [2,3,4], [[1,1,0,4],[2,2,1,9]], [1,2,1]
Output: 11
Explanation:
The price of A is 2,and 2 , a n d 3 for B, 4forC.Youmaypay 4 f o r C . Y o u m a y p a y 4 for 1A and 1B, and 9for2A,2Band1C.Youneedtobuy1A,2Band1C,soyoumaypay 9 f o r 2 A , 2 B a n d 1 C . Y o u n e e d t o b u y 1 A , 2 B a n d 1 C , s o y o u m a y p a y 4 for 1A and 1B (special offer #1), and 3for1B, 3 f o r 1 B , 4 for 1C.
You cannot add more items, though only $9 for 2A ,2B and 1C.

题目要求购物的总金额最小,这里给定三个参数public int shoppingOffers(List<Integer> price, List<List<Integer>> special, List<Integer> needs),第一个参数代表价格集合,第二个参数代表存在的套餐,第三个参数代表需要的商品的数量。
按照Example 1:进行分析就是:题目中给定的价格集合为[2,5]表示,商品A的价格为2,商品B的价格为5;第二个参数,给定的是[[3,0,5], [1,2,10]]表示给定两个优惠套餐,套餐一:买3个A,0个B一共花费5元,套餐二:1个A,2个B花费10;第三个参数,[3,2]表示商品A买3个,商品B卖2个。

现在要求买到的商品一定要与需要购买的商品个数完全一样,不能大于需要购买的商品数,求所有购买方案中花钱做少的那个花了多少钱。

解题思路

使用回溯+DFS,这里需要比较直接买和使用套餐的情况,而且可以一部分使用套餐一部分使用递归

AC代码

class Solution  {
    public int shoppingOffers(List<Integer> price, List<List<Integer>> special, List<Integer> needs) {
        return shopping(price, special, needs, 0);
    }

    private int shopping(List<Integer> price, List<List<Integer>> special, List<Integer> needs, int index) {
        //用来记录如果直接买这些商品需要花费的价格
        int local_min = direction(price, needs);

        for(int i = index; i < special.size(); i++) {
            //当前商品还有多少需要买
            List<Integer> needsLeft = new ArrayList<>();
            //当前是第i个特价的special List
            List<Integer> offer = special.get(i);
            //遍历needs需要多少商品个数的集合,知道遍历到最后一个商品个数为止
            for(int j = 0; j < needs.size(); j ++) {
                //如果需要的商品个数小于特价套餐中提供的个数,则不符合条件直接返回
                //因为题意要求必须买正好个数的商品,不可以多买
                //如果不符合题意,则将剩余的商品变量置为null
                if(needs.get(j) < offer.get(j)) {
                    needsLeft = null;
                    break;
                }
                //将每个商品剩余的数量添加到needsLeft集合中
                needsLeft.add(needs.get(j) - offer.get(j));
            }
            //如果needsLeft集合不为Null,则说明前面的特价商品满足题意,则递归向下判断
            if(needsLeft != null) {
                local_min = Math.min(local_min, offer.get(offer.size() - 1) + shopping(price, special, needsLeft, i));
            }
        }
        return local_min;
    }

    private int direction(List<Integer> price, List<Integer> needs) {
        int total = 0;
        for(int i = 0; i < needs.size(); i++) {
            total += price.get(i) * needs.get(i);
        }
        return total;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值