目录
题目:
c++解法:
题意
思路
代码
代码详解:
python3解法:
算法描述:
代码:
代码详解:
「云闪付」作为各方联手打造的全新移动端统一入口,致力成为消费者省钱省心的移动支付管家。
请你设计一个「云闪付」优惠活动管理系统 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^3
0 <= actId, userId <= 1000
1 <= discount < priceLimit <= 10^5
1 <= cost <= 10^5
1 <= number <= 1000
1 <= userLimit <= 10
c++解法:
哈希表
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 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 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 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 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
,表示一个用户参加了该活动,活动的可用数量减少了一个。这个方法的主要目的是在用户消费时,查找适用于用户的最大折扣活动,然后更新活动记录和剩余数量,最后计算用户实际支付的金额。这使得系统能够管理不同的优惠活动,确保用户获得适用的折扣。