目录
「云闪付」作为各方联手打造的全新移动端统一入口,致力成为消费者省钱省心的移动支付管家。
请你设计一个「云闪付」优惠活动管理系统 DiscountSystem,具体功能如下:
AddActivity(int actId, int priceLimit, int discount, int number, int userLimit) -- 表示创建编号为 actId 的优惠减免活动:
priceLimit 时,可享受 discount 的减免userLimit 次number 数量的参加名额RemoveActivity(actId) -- 表示结束编号为 actId 的优惠活动
Consume(int userId, int cost) -- 表示用户 userId 产生了一笔原价为 cost 的消费。请返回用户的实际支付金额。
注:若有多个优惠减免最大的活动,优先参加
actId最小的活动
注意:
actId 全局唯一示例 1:
输入:
["DiscountSystem","addActivity","consume","removeActivity","consume"][[],[1,15,5,7,2],[101,16],[1],[102,19]]输出:
[null,null,11,null,19]解释:
DiscountSystem obj = DiscountSystem(); // 初始化系统
obj.addActicity(1,15,5,7,2); //创建编号1的优惠活动,单笔消费原价不小于15时,
可享受5的减免,优惠活动共有7个名额,每个用户最多参与该活动2次
obj.consume(101,16); //用户101消费了16,满足优惠活动1条件,返回实际支付16 - 5 = 11
obj.removeActivity(1); // 结束编号为1的优惠活动
obj.consume(102,19); //用户101消费了19,目前不存在任何优惠活动,需按原价支付,返回19
示例 2:
输入:
["DiscountSystem","addActivity","addActivity","consume","removeActivity","consume","consume","consume","consume"][[],[1,10,6,3,2],[2,15,8,8,2],[101,13],[2],[101,17],[101,11],[102,16],[102,21]]输出:
[null,null,null,7,null,11,11,10,21]解释:
DiscountSystem obj = DiscountSystem(); // 初始化系统
obj.addActivity(1,10,6,3,2); // 创建编号1的优惠活动,单笔消费原价不小于10时,
可享受6的减免,优惠活动共有3个名额,每个用户最多参与该活动2次
obj.addActivity(2,15,8,8,2); // 创建编号2的优惠活动,单笔消费原价不小于15时,
可享受8的减免,优惠活动共有8个名额,每个用户最多参与该活动2次
obj.consume(101,13); // 用户101消费了13,仅满足优惠活动1条件,返回实际支付13 - 6 = 7
用户101参加1次活动1,活动1剩余2个名额
obj.consume(101,8); // 用户101消费了8,不满足任何活动,返回支付原价8
obj.removeActivity(2); // 结束编号为2的活动
obj.consume(101,17); // 用户101消费了17,满足优惠活动1条件,返回实际支付17 - 6 = 11
用户101参加2次活动1,活动1剩余1个名额
obj.consume(101,11); // 用户101消费了11,满足优惠活动1条件,但已达到参加次数限制,返回支付原价11
obj.consume(102,16); // 用户102消费了16,满足优惠活动1条件,返回实际支付16 - 6 = 10
用户102参加1次活动1,活动1无剩余名额
obj.consume(102,21); // 用户102消费了21,满足优惠活动1条件,但活动1已无剩余名额,返回支付原价21
提示:
1 <= addActicity, removeActivity, consume 累计操作数 <= 10^30 <= actId, userId <= 10001 <= discount < priceLimit <= 10^51 <= cost <= 10^51 <= number <= 10001 <= userLimit <= 10c++解法:哈希表
Activity的信息,分别存储:priceLimit: 允许折扣的价格int discount: 折扣的金额number: 当前还剩余多少个名额userLimit: 每个用户的优惠限制次数record: 记录每个用户已经使用的优惠的次数。API进行操作:addActivity: 生成一个新的Activity即可。removeActivity:从列表中将去删除即可。consume:这部稍微复杂点,首先找到最大可能的优惠,满足的前提是当前priceLimit >= cost,number > 0, record[userid] < userLimit,满足以上三个条件就记录下该Activity的id以及优惠。 找到最大的优惠后,对应Activity信息更新,主要涉及到number与record的更新即可。, addActivity与removeActivity均为 , consume为,其中
Activity的数量。Activity的数量。- struct Activity {
- int priceLimit;
- int discount;
- int number;
- int userLimit;
- unordered_map<int, int> record;
- Activity(int priceLimit, int discount, int number, int userLimit){
- this->priceLimit = priceLimit;
- this->discount = discount;
- this->number = number;
- this->userLimit = userLimit;
- }
- };
-
- class DiscountSystem {
- private:
- map<int, Activity *> cnt;
- public:
- DiscountSystem() {
-
- }
-
- void addActivity(int actId, int priceLimit, int discount, int number, int userLimit) {
- cnt[actId] = new Activity(priceLimit, discount, number, userLimit);
- }
-
- void removeActivity(int actId) {
- cnt.erase(actId);
- }
-
- int consume(int userId, int cost) {
- int maxdiscount = 0;
- int id = -1;
- for(auto &[actId, pAct]: cnt) {
- if(cost >= pAct->priceLimit) {
- if(pAct->discount > maxdiscount && pAct->number > 0) {
- if(pAct->record.count(userId)){
- if(pAct->record[userId] < pAct->userLimit){
- maxdiscount = pAct->discount;
- id = actId;
- }
- }else{
- maxdiscount = pAct->discount;
- id = actId;
- }
- }
- }
- }
- if(id >= 0){
- cnt[id]->record[userId]++;
- cnt[id]->number--;
- }
- return cost - maxdiscount;
- }
- };
这段C++代码定义了两类,Activity 和 DiscountSystem,并提供了与折扣活动和消费相关的功能。让我逐个部分详细解释:
- struct Activity {
- int priceLimit;
- int discount;
- int number;
- int userLimit;
- unordered_map<int, int> record;
-
- Activity(int priceLimit, int discount, int number, int userLimit) {
- this->priceLimit = priceLimit;
- this->discount = discount;
- this->number = number;
- this->userLimit = userLimit;
- }
- };
Activity 结构体:这个结构体表示一个折扣活动。它包括了以下成员变量:
priceLimit:价格限制,用户的消费金额必须达到或超过此限制才能参与活动。discount:折扣金额,表示用户在参与活动时可以获得的折扣金额。number:剩余活动数量,表示这个活动还剩下多少个名额。userLimit:用户参与次数限制,表示一个用户最多可以参与活动的次数。record:使用无序映射(unordered_map)记录每个用户参与活动的次数。Activity 结构体的构造函数:构造函数用于初始化 Activity 对象的各个成员变量。在对象创建时,将传入的参数值分配给相应的成员变量。
- class DiscountSystem {
- private:
- map<int, Activity *> cnt;
-
- public:
- DiscountSystem() {
- }
-
- void addActivity(int actId, int priceLimit, int discount, int number, int userLimit) {
- cnt[actId] = new Activity(priceLimit, discount, number, userLimit);
- }
-
- void removeActivity(int actId) {
- cnt.erase(actId);
- }
-
- int consume(int userId, int cost) {
- int maxdiscount = 0;
- int id = -1;
- for (auto &[actId, pAct] : cnt) {
- if (cost >= pAct->priceLimit) {
- if (pAct->discount > maxdiscount && pAct->number > 0) {
- if (pAct->record.count(userId)) {
- if (pAct->record[userId] < pAct->userLimit) {
- maxdiscount = pAct->discount;
- id = actId;
- }
- } else {
- maxdiscount = pAct->discount;
- id = actId;
- }
- }
- }
- }
- if (id >= 0) {
- pAct->record[userId]++;
- pAct->number--;
- }
- return cost - maxdiscount;
- }
- };
DiscountSystem 类:这个类用于管理折扣活动和消费的主要功能。它包括以下成员变量和方法:
cnt:使用 map 存储不同折扣活动的信息,每个活动由一个唯一的 actId 标识,并关联到相应的 Activity 对象指针。DiscountSystem 类的构造函数:构造函数为空,表示在创建 DiscountSystem 对象时不需要额外的初始化操作。
addActivity 方法:这个方法用于添加新的折扣活动。它接受 actId 以及与该活动相关的 priceLimit、discount、number 和 userLimit。在内部,它创建一个新的 Activity 对象,并将其与 actId 关联,然后将该关联添加到 cnt 中。
removeActivity 方法:这个方法用于移除指定的折扣活动。它接受一个 actId 参数,然后在 cnt 中查找并删除与该 actId 相关的 Activity 对象。
consume 方法:这是核心的消费方法。它接受 userId 和 cost 作为参数,用于模拟用户的消费操作并计算折扣。以下是详细解释:
maxdiscount 和 id,分别用于跟踪用户能够获得的最大折扣金额和适用的活动标识。for 循环遍历 cnt 中的活动,其中 auto &[actId, pAct] 允许同时迭代活动的标识和对应的 Activity 对象指针。maxdiscount 和 id。id >= 0),则更新相应的 Activity 对象的记录和剩余数量,并返回用户实际支付的金额(原始消费减去最大折扣)代码建立了两个类:Activity和DiscountSystem,用于管理优惠活动和消费记录。
Activity 类:
这个类代表了一个优惠活动。它的构造函数 __init__ 接受四个参数:priceLimit(价格限制)、discount(折扣)、number(活动数量)、和 userLimit(用户限制)。
这些参数分别表示:活动的价格限制(只有当消费满足该限制时才能参加活动)、折扣金额、活动的剩余数量、和每个用户可参加活动的次数。
record 字典用于跟踪每个用户参加活动的次数。
DiscountSystem 类:
这个类用于管理多个不同的优惠活动。它的构造函数 __init__ 初始化一个空的 activities 字典,用于存储活动的信息。
addActivity 方法:
这个方法用于向 DiscountSystem 中添加新的优惠活动。
它接受 actId(活动的唯一标识符)以及与该活动相关的 priceLimit、discount、number 和 userLimit。
通过调用 Activity 的构造函数创建一个新的活动对象,并将其存储在 activities 字典中。
removeActivity 方法:
这个方法用于从 DiscountSystem 中删除特定的优惠活动,通过提供 actId 来指定要删除的活动。
consume 方法:
这个方法用于用户消费时查找适用于用户的最大折扣。
它接受 userId(用户标识符)和 cost(消费金额)作为参数。
方法遍历 activities 字典,查找用户满足价格限制的活动,然后比较这些活动的折扣和用户的历史参加次数,以确定用户可以享受的最大折扣。
如果找到适用的活动,它会更新 Activity 对象的 record 和 number 字段,并返回最终消费金额减去折扣金额。
总之,这个代码演示了一个优惠活动管理系统,用户可以通过 DiscountSystem 添加和删除不同的活动,然后在消费时根据条件享受相应的折扣。活动的参与次数和剩余数量也得到了跟踪。
时间复杂度分析:
这个系统的时间复杂度主要受到两个因素的影响:
添加活动 (addActivity):这是一个O(1)的操作,因为它只涉及将新活动添加到字典中。
用户消费 (consume):在最坏情况下,需要遍历所有活动,所以它的时间复杂度是O(n),其中n是活动的数量。
- class Activity:
- def __init__(self, priceLimit, discount, number, userLimit):
- self.priceLimit = priceLimit
- self.discount = discount
- self.number = number
- self.userLimit = userLimit
- self.record = {}
-
- class DiscountSystem:
- def __init__(self):
- self.activities = {}
-
- def addActivity(self, actId, priceLimit, discount, number, userLimit):
- self.activities[actId] = Activity(priceLimit, discount, number, userLimit)
-
- def removeActivity(self, actId):
- del self.activities[actId]
-
- def consume(self, userId, cost):
- maxdiscount = 0
- id = -1
- for actId, pAct in self.activities.items():
- if cost >= pAct.priceLimit:
- if pAct.discount > maxdiscount and pAct.number > 0:
- if userId in pAct.record:
- if pAct.record[userId] < pAct.userLimit:
- maxdiscount = pAct.discount
- id = actId
- else:
- maxdiscount = pAct.discount
- id = actId
- if id >= 0:
- self.activities[id].record[userId] = self.activities[id].record.get(userId, 0) + 1
- self.activities[id].number -= 1
- return cost - maxdiscount
- class Activity:
- def __init__(self, priceLimit, discount, number, userLimit):
- self.priceLimit = priceLimit
- self.discount = discount
- self.number = number
- self.userLimit = userLimit
- self.record = {}
这部分定义了 Activity 类。这个类有一个构造函数 __init__,它接受四个参数:priceLimit、discount、number 和 userLimit。这些参数代表了活动的价格限制、折扣、剩余数量和用户限制。同时,创建了一个空字典 record 用于跟踪用户参与活动的次数。
- class DiscountSystem:
- def __init__(self):
- self.activities = {}
在这里,定义了 DiscountSystem 类,它包含一个构造函数 __init__,该构造函数初始化一个空的字典 activities,用于存储不同活动的信息。
- def addActivity(self, actId, priceLimit, discount, number, userLimit):
- self.activities[actId] = Activity(priceLimit, discount, number, userLimit)
这是 DiscountSystem 类的一个方法,addActivity。它接受 actId(活动的唯一标识符)以及与该活动相关的 priceLimit、discount、number 和 userLimit。方法的作用是将一个新的 Activity 对象添加到 activities 字典中,使用 actId 作为键。
- def removeActivity(self, actId):
- del self.activities[actId]
这是 DiscountSystem 类的另一个方法,removeActivity。它接受 actId 作为参数,用于从 activities 字典中删除指定的活动。
- def consume(self, userId, cost):
- maxdiscount = 0
- id = -1
- for actId, pAct in self.activities.items():
- if cost >= pAct.priceLimit:
- if pAct.discount > maxdiscount and pAct.number > 0:
- if userId in pAct.record:
- if pAct.record[userId] < pAct.userLimit:
- maxdiscount = pAct.discount
- id = actId
- else:
- maxdiscount = pAct.discount
- id = actId
- if id >= 0:
- self.activities[id].record[userId] = self.activities[id].record.get(userId, 0) + 1
- self.activities[id].number -= 1
- return cost - maxdiscount
maxdiscount 和 id 的初始化:
maxdiscount 用于跟踪用户可以享受的最大折扣金额。初始值设为0。id 用于记录适用于用户的活动的标识符。初始值设为-1,表示未找到适用的活动。迭代活动:
for actId, pAct in self.activities.items(): 这一行开始迭代 activities 字典中的每个活动。actId 是活动的唯一标识符,pAct 是与该标识符相关联的 Activity 对象。检查价格限制:
if cost >= pAct.priceLimit: 这一行检查用户的消费金额是否达到了当前活动的价格限制。只有当消费满足价格限制时,才会考虑这个活动。检查折扣和剩余数量:
if pAct.discount > maxdiscount and pAct.number > 0: 这一行检查当前活动的折扣是否大于已经记录的最大折扣(maxdiscount),并且该活动的剩余数量(number)是否大于0。检查用户记录:
if userId in pAct.record: 这一行检查用户是否在当前活动的记录中。如果用户之前参加过该活动,就需要检查用户是否达到了参加活动的次数限制。if pAct.record[userId] < pAct.userLimit: 如果用户的参与次数未达到限制,将更新 maxdiscount 为该活动的折扣金额,并将 id 设置为当前活动的标识符。用户未在记录中的情况:
maxdiscount 设置为该活动的折扣金额,并将 id 设置为当前活动的标识符。应用折扣和更新记录:
id 大于等于0,表示找到了适用的活动,将会执行以下步骤:
Activity 对象的 record 字典,将用户标识符 userId 对应的值加1,表示用户参加了该活动。number,表示一个用户参加了该活动,活动的可用数量减少了一个。这个方法的主要目的是在用户消费时,查找适用于用户的最大折扣活动,然后更新活动记录和剩余数量,最后计算用户实际支付的金额。这使得系统能够管理不同的优惠活动,确保用户获得适用的折扣。