持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情
前言
小白算法比较菜,希望能激励我每日更新,从leetcode第一题开始,2022年目标300题,记录从0到1的全过程!!
中国银联专场竞赛(2023届校园招聘专场)
中国银联专场竞赛(2023届校园招聘专场)-力扣
这个比赛当时没看到,参加的人不多,后来自己做发现并不难,四题都能a了,咱就分三期讲讲这四个题啦。
这个题题目长的吓死人,大家千万别被吓到了,其实不难。
银联-4. 设计自动售货机
「银联二维码」支付可以提供简便、顺畅的消费服务,通过出示二维码或扫描二维码即可完成支付。
现有一台使用银联二维码进行支付的自动售货机,并对使用 银联 支付的用户提供额外的优惠服务。
同一名顾客每成功购买一次,下次购买便可多享受 1% 的折扣(折后价向上取整),最低折扣为 70%
- 即:第一次购买支付 100% 费用,第二次购买支付 99% 费用, 第三次购买支付 98% 费用,以此类推。
请你设计一个自动售货机,你需要实现一个 VendingMachine 类:
-
VendingMachine()—— 初始化一个VendingMachine实例 -
void addItem(int time, int number, string item, int price, int duration)—— 在time时刻向售货机中增加number个名称为item的商品,价格为price,保质期为duration- 同种商品可能有不同批次,不同批次的价格和保质期可能不同
-
long sell(int time, string customer, string item, int number)—— 在time时刻,名称为customer的顾客前来购买了number个名称为item的商品,返回总费用- 当且仅当售货机中存在足够数量的未过期商品方可成功购买,并返回支付的总费用,否则一件商品也不会售出,并返回
-1 - 对于价格不同的同种商品,优先售出价格最低的商品;
- 如果有价格相同的同种商品,优先出售距离过期时间最近的商品;
- 当且仅当售货机中存在足够数量的未过期商品方可成功购买,并返回支付的总费用,否则一件商品也不会售出,并返回
注意:
- 输入保证前一次操作的
time不大于后一次操作的time - 过期指商品存入的时刻与保质期之和小于当前时刻,也即
addtime + duration < currTime
示例 1
输入:
["VendingMachine","addItem","sell","sell","sell","sell"]
[[],[0,3,"Apple",10,10],[1,"Tom","Apple",1],[2,"Tom","Apple",3],[3,"Mary","Banana",2],[11,"Jim","Apple",1]]
输出: [null,null,10,-1,-1,-1]
解释:
VendingMachine sys = new VendingMachine();
sys.addItem(0,3,"Apple",10,10); // 时刻 0 ,添加 3 个 Apple,价格为 10,保质期为 10。
sys.sell(1,"Tom","Apple",1); // 时刻 1 ,用户 Tom 购买 1 个 Apple, 支付 10 :。
sys.sell(2,"Tom","Apple",3); // 时刻 2 ,售货机中 Apple 数量为 2 ,用户 Tom 购买失败,返回 -1。
sys.sell(3,"Mary","Banana",2); // 时刻 3 ,售货机中没有 Banana ,用户 Mary 购买失败,返回 -1。
sys.sell(11,"Jim","Apple",1); // 时刻 11 ,售货机中的 Apple 全部过期,用户 Jim 购买失败,返回 -1。
示例 2
输入:
["VendingMachine","addItem","addItem","sell","addItem","sell","sell","sell","addItem","sell","sell"]
[[],[0,1,"Apple",4,3],[1,3,"Apple",4,2],[2,"Mary","Apple",2],[2,1,"Banana",2,5],[4,"Jim","Banana",2],[4,"Mary","Banana",1],[4,"Mary","Apple",1],[6,200,"Apple",2,5],[6,"Jim","Apple",100],[7,"Mary","Apple",100]]
输出: [null,null,null,8,null,-1,2,-1,null,200,196]
解释:
VendingMachine sys = new VendingMachine();
sys.addItem(0,1,"Apple",4,3); // 时刻 0 ,添加 1 个 Apple,价格为 4,保质期为 3。
sys.addItem(1,3,"Apple",4,2); // 时刻 1 ,添加 3 个 Apple,价格为 4,保质期为 2。
sys.sell(2,"Mary","Apple",2); // 时刻 2 ,用户 Mary 购买 2 个 Apple,支付 8。
sys.addItem(2,1,"Banana",2,5); // 时刻 2 ,添加 1 个 Banana,价格为 2,保质期为 5。
sys.sell(4,"Jim","Banana",2); // 时刻 4 ,售货机中 Banana 数量为 1 ,用户 Jim 购买失败,返回 -1。
sys.sell(4,"Mary","Banana",1); // 时刻 4 ,用户 Mary 购买 1 个 Banana,享受 1% 的优惠,向上取整后为 2
sys.sell(4,"Mary","Apple",1); // 时刻 4 ,售货机中的 Apple 全部过期,用户 Mary 购买失败,返回 -1。
sys.addItem(6,200,"Apple",2,5); // 时刻 6 ,添加 200 个 Apple,价格为 2,保质期为 5。
sys.sell(6,"Jim","Apple",100); // 时刻 6 ,用户 Jim 购买 100 个 Apple。返回 200
sys.sell(7,"Mary","Apple",100); // 时刻 7 ,用户 Mary 购买 100 个 Apple,可享受 2% 的优惠。返回196
提示
1 <= item.length,customer.length <= 10,item和customer中只包含英文字母1 <= duration,price,number <= 10^60 <= time <= 10^6addItem和sell的总调用次数不超过1000次
代码
大家耐心把题目看完之后,那么我梳理以下几点
1.我们要实现两个功能,添加物品,和售卖物品
2.添加物品比较简单的,直接添加就可以了
3.售卖物品,优先售卖便宜的,同价格售卖保质期近的,超过保质期的不卖,如果数量不过就一个都不卖,根据用户来访频次打折
设计如下 1.用一个 HashMap<String, Integer> customerMap 存储用户来购买过几次,最多只能存30。
2.用一个HashMap<String, PriorityQueue<int[]>> map 存售货机里面的商品,这个queue里面装的是一个长度为3的数组分别代表int[0]是价格 int[1]是过期时间(time + durtion)int[3]是数量number,并根据int[0]和int[1]排序
3.顾客来买东西的时候,需要考虑符合条件的商品数量够不够,所以需要先统计符合条件的数量,如果不够卖,直接返回-1
4.如果够卖,那就开始卖货,从map中取出对应商品的queue,一个一个拿出来买,直到数量等于顾客需要的数量即可。并实时计算价格。
5.最后根据customerMap中顾客购买的次数进行折扣返回。并更新customerMap
注意点: 1.计算价格的时候会超int,所以要用long。
2.在售卖过程中如果发现过期的商品会从queue中poll出来,会减小内存占用
3.顾客购物时,可能需要从queue中取出好几个,最后一个如果还剩10个库存,顾客只购买5个,记得需要更新number后,重新把这个数组add到queue中去。
class VendingMachine {
HashMap<String, PriorityQueue<int[]>> map = new HashMap<>();
HashMap<String, Integer> customerMap = new HashMap<>();
public VendingMachine() {
// 价格-时间(time + durtion)- number
PriorityQueue<int[]> queue = new PriorityQueue<>(new Comparator<int[]>() {
@Override
public int compare(int[] a1, int[] a2) {
if (a1[0] == a2[0]) {
return a1[1] - a2[1];
}
return a1[0] - a2[0];
}
});
}
public PriorityQueue getQueue() {
PriorityQueue<int[]> queue = new PriorityQueue<>(new Comparator<int[]>() {
@Override
public int compare(int[] a1, int[] a2) {
if (a1[0] == a2[0]) {
return a1[1] - a2[1];
}
return a1[0] - a2[0];
}
});
return queue;
}
public void addItem(int time, int number, String item, int price, int duration) {
PriorityQueue<int[]> orDefault = map.getOrDefault(item, getQueue());
int[] ints = new int[]{price, duration + time, number};
orDefault.add(ints);
map.put(item,orDefault);
}
public long sell(int time, String customer, String item, int number) {
PriorityQueue<int[]> queue = map.getOrDefault(item, new PriorityQueue<>());
//判断够不够卖
int sum = 0;
for (int[] arr : queue) {
if (time <= arr[1]) {
sum += arr[2];
}
}
if (sum < number) {
return -1L;
}
double res = 0;
while (true) {
int[] poll = queue.poll();
if (poll[1] >= time) {
if (poll[2] >= number) {
res = res + (long)poll[0] * number;
poll[2] = poll[2] - number;
if (poll[2] > 0) {
queue.add(poll);
}
break;
} else {
res = res + (long)poll[0] * poll[2];
number = number - poll[2];
}
}
}
Integer customerTime = customerMap.getOrDefault(customer, 0);
customerMap.put(customer,customerTime+1);
customerTime = Math.min(30, customerTime);
return (long)Math.ceil(res * (100 - customerTime) / 100);
}
}
耗时其实差的不远,并没有几倍甚至是数量级的差距。
两次提交的运行时间也有所差异,大家看这个运行时间时,只要没有数量级的差异,基本没太大问题
第一、二题连接如下-银联-1. 重构链表-银联-2. 勘探补给
银联-1. 重构链表-银联-2. 勘探补给
第三题连接如下-银联-3. 风能发电
银联-3. 风能发电
3.结束
前两题都不难,基本100题量的同学就可以做出来了,这个题明白业务逻辑也是可以做出来的,基本刷个200题就能达到了,gogogo,刷题刷题,每天一道,三年1000道!!!!