LeetCode-第五个星期

大礼包

LeetCode638题,购买指定数量的商品,可以单独购买,也可以购买套餐,问最优惠的购买方式需要花费多少钱。

在LeetCode商店中, 有许多在售的物品。

然而,也有一些大礼包,每个大礼包以优惠的价格捆绑销售一组物品。

现给定每个物品的价格,每个大礼包包含物品的清单,以及待购物品清单。请输出确切完成待购清单的最低花费。

每个大礼包的由一个数组中的一组数据描述,最后一个数字代表大礼包的价格,其他数字分别表示内含的其他种类物品的数量。

任意大礼包可无限次购买。

示例 1:

输入: [2,5], [[3,0,5],[1,2,10]], [3,2]
输出: 14
解释: 
有A和B两种物品,价格分别为¥2和¥5。
大礼包1,你可以以¥5的价格购买3A和0B。
大礼包2, 你可以以¥10的价格购买1A和2B。
你需要购买3个A和2个B, 所以你付了¥10购买了1A和2B(大礼包2),以及¥4购买2A。
示例 2:

输入: [2,3,4], [[1,1,0,4],[2,2,1,9]], [1,2,1]
输出: 11
解释: 
A,B,C的价格分别为¥2,¥3,¥4.
你可以用¥4购买1A和1B,也可以用¥9购买2A,2B和1C。
你需要买1A,2B和1C,所以你付了¥4买了1A和1B(大礼包1),以及¥3购买1B, ¥4购买1C。
你不可以购买超出待购清单的物品,尽管购买大礼包2更加便宜。
说明:

最多6种物品, 100种大礼包。
每种物品,你最多只需要购买6个。
你不可以购买超出待购清单的物品,即使更便宜。

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

思路分析:
1.从现有礼包中选择符合条件的礼包(不能出现某商品数量大于需求商品的数量)
2.同款礼包可以多次选择,并且同款礼包的选择次数不同,对最终计算的价格也不同,原因在于可以选择不同的礼包(迭代)
3.最终礼包的数量需要单独付款时,需要单独计算

private static int res = 0;
    private static int sum = 0;
    private static List<Integer> global_needs;
    private static List<Integer> global_price;
    private static List<List<Integer>> global_special;

    public static int shoppingOffers(List<Integer> price, List<List<Integer>> special, List<Integer> needs) {
        for (int i = 0; i < needs.size(); i++) {
            res += price.get(i) * needs.get(i);
        }
        global_needs = new ArrayList<>(needs);
        global_price = new ArrayList<>(price);
        global_special = new ArrayList<>(special);
        find(0);
        return res;
    }

    public static void find(int index) {
        for (int i = index; i < global_special.size(); i++) {
            List<Integer> item = global_special.get(i);
            //计算当前下标的礼包可以购买的最大数量
            int buyMaxSum = cal_special_num(item);
            if (buyMaxSum != 0) {
                //至少可以购买一次,需要循环同一个礼包购买的次数,会产生其余礼包的不同购买
                for (int j = 1; j <= buyMaxSum; j++) {
                    //记录目前的金额和所需的商品的剩余数量
                    int tempSum = sum;
                    List<Integer> tempList = new ArrayList<>(global_needs);
                    //当前金额加当前礼包的价格乘数量
                    sum += item.get(item.size() - 1) * j;
                    for (int k = 0; k < global_price.size(); k++) {
                        //所需商品的剩余数量减去对应礼包中的商品数量乘礼包数
                        global_needs.set(k, global_needs.get(k) - item.get(k) * j);
                    }
                    //迭代寻找下一个套餐
                    find(i + 1);
                    //最终返回的global_needs肯定是所有套餐都不满足的
                    for (int k = 0; k < global_needs.size(); k++) {
                        //计算单个购买的价格
                        sum += global_needs.get(k) * global_price.get(k);
                    }
                    //比较目前最小的价格和当前价格的大小
                    res = Math.min(res, sum);
                    //恢复开始的金额和剩余数量,j++则多购买一个当前数量的礼包
                    sum = tempSum;
                    global_needs = tempList;
                }
            }
        }
    }

    private static int cal_special_num(List<Integer> item) {
        int max = Integer.MAX_VALUE;
        for (int i = 0; i < global_needs.size(); ++i) {
            if (global_needs.get(i) < item.get(i))
                return 0;
            if (item.get(i) != 0)
                max = Math.min(global_needs.get(i) / item.get(i), max);
        }
        return max;
    }

正方形数组的数目

一个数组允许调换元素的顺序,使得相邻元素相加得到的数是一个完全平方根,问不同的排列有几种?
在这里插入图片描述
思路分析:该题的难点在于如何保证,这次满足正方形数组的顺序,不和前面的情况一致,关于寻找正方形数组的问题,只需要通过迭代即可。我们可以把数组排序,这样相同的数就聚在一起了,通过判断来达到去重的目的。

private static int res;
    private static boolean visited[];

    public static void main(String[] args) {
        System.out.println(numSquarefulPerms(new int[]{5,11,5,4,5}));
    }
    public static int numSquarefulPerms(int[] A) {
        //排序后将相同元素放在一起
        Arrays.sort(A);
        visited = new boolean[A.length];
        dfs(A, -1, 0);
        return res;
    }

    private static void dfs(int[] arr, int pre, int count) {
        if (count >= arr.length) {
            res++;
        }
        for (int i = 0; i < arr.length; i++) {
            // 减枝+去重
            if (visited[i] || (pre != -1 && !isSquare(pre + arr[i])) || (i != 0 && arr[i] == arr[i - 1] && !visited[i - 1])) {
                continue;
            }
            visited[i] = true;
            dfs(arr, arr[i], count + 1);
            visited[i] = false;
        }
    }

    // 用来判断是否是完全平方数
    private static boolean isSquare(int num) {
        double sqrt = Math.sqrt(num);
        return sqrt - (int) sqrt == 0;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值