当前位置: 首页 > news >正文

Leetcode刷题Python之638.大礼包

提示:这道题是典型的“选择问题”。

文章目录

  • 一、题目描述
    • 题目内容
    • 示例:
  • 二、题目解析
    • 思路分析
  • 三、代码实现
    • 详细解释
  • 四、总结
    • 时间复杂度和空间复杂度分析
    • 评价


一、题目描述

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

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

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

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

我们的目标是在满足购物清单的前提下,通过购买商品或使用大礼包来实现最低花费。

题目内容

price:一个长度为 n 的整数数组,表示每件商品的单价。
special:一个二维数组,每个子数组代表一个大礼包,前 n 个数字表示礼包中包含的各商品数量,最后一个数字为礼包总价。
needs:一个长度为 n 的数组,表示每件商品的需求数量。

示例:

示例1 :输入:price = [2,5], special = [[3,0,5],[1,2,10]], needs = [3,2]
输出:14
解释:有 A 和 B 两种商品,单价分别为 ¥2 和 ¥5 。大礼包 1,可以以 ¥5 购买 3A 和 0B。大礼包 2,可以以 ¥10 购买 1A 和 2B。为了满足需求 3A 和 2B,可用大礼包 2(花费 ¥10),再单独购买 2A(花费 ¥4),总共花费 ¥14。

二、题目解析

1.需求限制:购买的大礼包内物品数量不能超过需求,也就是说不能超量购买商品。

2.无限次购买礼包:只要满足需求,礼包可以多次购买,但每次购买会消耗一定成本。

3.求最小总花费:我们既可以选择单独购买商品,也可以组合使用大礼包,求最小的满足需求的总花费。

思路分析

这个问题可以分解成每一步选择用或者不用大礼包的组合问题。我们可以使用递归的深度优先搜索(DFS)来尝试每种情况,并使用记忆化技术来优化重复计算。

1.基本方法

不使用大礼包时的总花费 = 每件商品需求数量 * 单价的总和。
尝试使用大礼包,在需求量范围内应用礼包来减少商品的需求量,并将剩余需求递归计算出花费。

2.递归策略

对于每种需求状态,计算出使用某个礼包后的新需求状态。
对比使用和不使用礼包的成本,取最小值作为当前需求状态的最小花费。

3.记忆化

为了避免重复计算,用一个字典 memo 来存储不同需求状态对应的最小花费。
当某个需求组合已经计算过时,直接取缓存结果。


三、代码实现

class Solution(object):def shoppingOffers(self, price, special, needs):""":type price: List[int]:type special: List[List[int]]:type needs: List[int]:rtype: int"""# 记忆化字典,用于存储每种需求状态下的最低花费memo = {}def dfs(current_needs):# 转换为元组,以便哈希存储needs_tuple = tuple(current_needs)# 如果当前需求状态已经在 memo 中,直接返回存储的最小花费if needs_tuple in memo:return memo[needs_tuple]# 不使用任何大礼包时的最低花费,即逐件单独购买的总花费min_cost = sum(need * price[i] for i, need in enumerate(current_needs))# 遍历每个大礼包,尝试用礼包来满足当前需求for offer in special:# 用来存储新需求状态new_needs = []for i in range(len(current_needs)):# 如果某个商品在当前需求中少于礼包中的数量,无法使用该礼包if current_needs[i] < offer[i]:break# 减去礼包内商品数量,计算新的需求状态new_needs.append(current_needs[i] - offer[i])else:# 如果所有需求都满足礼包条件,递归计算剩余需求的最低花费min_cost = min(min_cost, dfs(new_needs) + offer[-1])# 存储当前需求状态下的最小花费,以便记忆化优化memo[needs_tuple] = min_costreturn min_cost# 从初始需求开始计算最低花费return dfs(needs)

详细解释

dfs函数:此函数用于深度优先搜索(DFS),在当前需求状态下递归尝试各种大礼包组合。

记忆化:memo字典缓存已经计算过的需求组合,以减少重复计算。

不使用礼包的情况:当不使用礼包时,直接按单价购买所需商品数量,计算的花费就是“每件商品需求数量 * 单价”的和。

礼包有效性检查:对每个礼包,逐一检查是否满足当前需求;如果任何一件商品的需求低于礼包内数量,跳过该礼包。

四、总结

时间复杂度和空间复杂度分析

时间复杂度:由于记忆化减少了重复计算,每种需求状态的复杂度取决于礼包数量和需求组合数。总体时间复杂度较难精确估计,但在给定数据约束下,表现稳定。

空间复杂度:主要是memo字典的空间开销,用于存储已计算过的需求状态。

评价

这道题是典型的“选择问题”:我们要在多种可能的选择中找到最优解。递归和记忆化的结合非常适合这种逐层拆分的组合问题。通过将每一种需求状态存储在记忆化字典中,我们显著提高了递归的效率。

在这里插入图片描述


http://www.mrgr.cn/news/64959.html

相关文章:

  • SVN 提交操作
  • MyBatis的高级映射及延迟加载
  • golang gin ShouldBind的介绍和使用
  • 程序《工资分类收税》
  • Python3 No module named ‘pymysql‘
  • ubuntu20.04 加固方案-检查是否设置登录超时
  • Windows配置Nodejs及nmp简明教程(2024可用)
  • 深入理解JavaScript中的 new 关键字
  • 【2024-10-31-2024-11-03】LeetCode刷题——python语法基础题
  • python如何调字体大小
  • 241029 网鼎杯青龙组 Crypto2
  • STM32 第22章 常用存储器介绍
  • 语音合成技术:AI如何模仿人类声音
  • PCI、USB、AGP、PCI-Express
  • 计算布尔二叉树的值
  • CleanShot X - Mac(苹果电脑)专业截图录屏软件
  • 移植 AWTK 到 纯血鸿蒙 (HarmonyOS NEXT) 系统 (6) - 触屏事件
  • mysql的存储函数
  • 《CLR via C#》读书笔记--CLR的执行模型
  • 小白投资理财 - 看懂布林线 BOLL
  • Android笔记(三十一):Deeplink失效问题
  • 英语写作中“出于……”out of的用法
  • 实习冲刺Day12
  • notify和notifyAll的区别,以及sleep、wait和join的区别
  • OPENAI官方建议
  • 推荐一款Windows维护和修复工具包:RepairKit