LeetCode高频题:Android系统中WakeLock防止手机进入睡眠模式,统计出每个应用对WakeLock的不同贡献值

LeetCode高频题:Android系统中WakeLock防止手机进入睡眠模式,统计出每个应用对WakeLock的不同贡献值

提示:本题是系列LeetCode的150道高频题,你未来遇到的互联网大厂的笔试和面试考题,基本都是从这上面改编而来的题目
互联网大厂们在公司养了一大批ACM竞赛的大佬们,吃完饭就是设计考题,然后去考应聘人员,你要做的就是学基础树结构与算法,然后打通任督二脉,以应对波云诡谲的大厂笔试面试题!
你要是不扎实学习数据结构与算法,好好动手手撕代码,锻炼解题能力,你可能会在笔试面试过程中,连题目都看不懂!比如华为,字节啥的,足够让你读不懂题
在这里插入图片描述


题目

一个大佬发我的题目,我帮忙看了看
在这里插入图片描述


一、审题

示例:
在这里插入图片描述
在这里插入图片描述

你们有没有觉得案例2有问题啊?
1245–1250,长度不是6啊
是5啊
对吧???????


二、解题

这题关键在哪里?

在俩交叉段中,有交集的你得平均,没有交集的你得算上
比如上面的案例2

1236–1238属于两个应用公有的段
这个只能算平均
3/2=1

没有交集的2个2直接加上

拢共5

在这里插入图片描述
但是1245–1250,就是6,没有交集,不平均

你最重要的就是搞清楚哪些段有交集?

比如对于当前1234–1240段cur,谁影响了我?
【影响我是啥意思?就是有的段,它的段尾,竟然>=cur的段首】
就是影响我cur
就上面1236–1238段,断尾1238>=cur的段首1234

那它一定影响cur
这种情况
我可以把交集段段首start【就是2段的段首最大值】和断尾end找出来【就是2段的段尾最小值】
在这里插入图片描述

没有交集的段首a就是就是2段的段首最小值
没有交集的段尾b就是就是2段的段尾最大值

这样的话,贡献值,就是
start-a+b-end+(end-start)/2
前面减的是非交集的前面段
中间减的是非交集的后面段
最后减的是交集的平均段

懂?

具体代码怎么模拟这个过程呢???
(1)先将所有的时间段变为Node,放入有序表,有序表按照start排序
(2)然后一鼓作气,把能相互影响的那几段,放入小根堆heap
(3)一旦有一段压根不想交的进来的话,先不要进堆,结算heap里面的结果,放入ans

然后回到(2)继续循环就行

最后ans就出来了

手撕代码如下:

import java.util.*;

    //看两端交叉,用堆模拟多少人公用
    public static class Solution{
        //应用占用时间段
        public static class Node{
            public int start;
            public int end;

            public Node(int s, int e){
                start = s;
                end = e;
            }
        }

        //排序比较器,根据start排序
        public static class cptr implements Comparator<Node>{
            @Override
            public int compare(Node o1, Node o2){
                return o1.start - o2.start;
            }
        }

        //然后开始模拟业务
        public List<Integer> getWakeLockContrib(List<List<Integer>> arr){
            TreeSet<Node> set = new TreeSet<>(new cptr());//有序表
            for(List<Integer> x:arr){
                for (int i = 0; i < x.size(); i+=2) {
                    set.add(new Node(x.get(i), x.get(i + 1)));//分别加入set
                }
            }
            //然后小根堆模拟交集最大的
            PriorityQueue<Node> heap = new PriorityQueue<>(new cptr());//小根堆
            List<Integer> ans = new ArrayList<>();//结果
            while (!set.isEmpty()) {
                while (heap.isEmpty() ||
                        (!set.isEmpty() && set.first().start <= heap.peek().end)){
                    heap.add(set.pollFirst());//有交集的进来
                }
                //不影响影响我cur的,就要结算heap里面的
                int start = Integer.MIN_VALUE;
                int end = Integer.MAX_VALUE;
                int k = 0;
                int a = Integer.MAX_VALUE;
                int b = Integer.MIN_VALUE;//这个记录非交叉的部分
                while (!heap.isEmpty()){
                    k++;//几个共享
                    Node node = heap.poll();
                    start = Math.max(start, node.start);
                    end = Math.min(end, node.end);//取交集
                    a = Math.min(a, node.start);//取非交集
                    b = Math.max(b, node.end);
                }
                if (start != Integer.MIN_VALUE && end != Integer.MAX_VALUE){
                    ans.add(b - end + start - a + (end - start) / k);//加入结果
                }
            }
            //最后一定会返回结果
            return ans;
        }
    }

然后测试:

案例1:

    public static void main(String[] args) {
        List<List<Integer>> arr = new ArrayList<>();
        List<Integer> tmp = new ArrayList<>();
        tmp.add(1234);
        tmp.add(1235);
        arr.add(tmp);
        tmp = new ArrayList<>();
        tmp.add(1236);
        tmp.add(1238);
        arr.add(tmp);

        Solution solution = new Solution();
        List<Integer> ans = solution.getWakeLockContrib(arr);
        for(Integer x:ans) System.out.println(x +" ");
    }

结果:
在这里插入图片描述

案例2:

    public static void main(String[] args) {
        List<List<Integer>> arr = new ArrayList<>();
        List<Integer> tmp = new ArrayList<>();
        tmp.add(1234);
        tmp.add(1240);
        arr.add(tmp);
        tmp = new ArrayList<>();
        tmp.add(1236);
        tmp.add(1238);
        tmp.add(1245);
        tmp.add(1250);
        arr.add(tmp);

        Solution solution = new Solution();
        List<Integer> ans = solution.getWakeLockContrib(arr);
        for(Integer x:ans) System.out.println(x +" ");
    }

结果:
在这里插入图片描述

非常稳
笔试过程中,可能:会出bug,想想逻辑,调试一下就知道自己错哪里了,慢慢就调试出来了


总结

提示:重要经验:

1)贪心的题目,一般就是排序+堆,典型的这种操作,大厂经常考,据说这个是OPPO23届秋招的题目
3)笔试求AC,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰露可乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值