[杨小白]_leetcode_中国银联专场竞赛-第四题

232 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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 <= 10item 和 customer 中只包含英文字母
  • 1 <= duration,price,number <= 10^6
  • 0 <= time <= 10^6
  • addItem 和 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);
        }
    }

耗时其实差的不远,并没有几倍甚至是数量级的差距。

image.png

两次提交的运行时间也有所差异,大家看这个运行时间时,只要没有数量级的差异,基本没太大问题

image.png

第一、二题连接如下-银联-1. 重构链表-银联-2. 勘探补给

银联-1. 重构链表-银联-2. 勘探补给

第三题连接如下-银联-3. 风能发电

银联-3. 风能发电

3.结束

前两题都不难,基本100题量的同学就可以做出来了,这个题明白业务逻辑也是可以做出来的,基本刷个200题就能达到了,gogogo,刷题刷题,每天一道,三年1000道!!!!