LeetCode 986, 1353

406 阅读1分钟

LeetCode 986

链接:leetcode.com/problems/in…

方法1:扫描线(不推荐,我就写着玩)

时间复杂度:O((m+n)log(m+n)), m = firstList.length, n = secondList.length 想法:我之前写区间的题写魔怔了,上去看了一眼数据规模,然后直接扫描线搞了,不过果然beat率非常低,我这里就是写写复习一下扫描线。就像天上有多少架飞机那道题,这里什么时候有俩正在进行的了就记一下起始时间,什么时候又变成只有一个会在开了就放进结果数组。 代码:

class Event {
    public int time, start;
    
    public Event(int time, int start) {
        this.time = time;
        this.start = start;
    }
}

class EventComparator implements Comparator<Event> {
    public int compare(Event e1, Event e2) {
        if (e1.time != e2.time) {
            return e1.time - e2.time;
        }
        return e1.start - e2.start;
    }
}

class Solution {
    public int[][] intervalIntersection(int[][] firstList, int[][] secondList) {
        List<Event> events = new ArrayList<>();
        for (int[] f : firstList) {
            events.add(new Event(f[0], 0));
            events.add(new Event(f[1], 1));
        }
        for (int[] s : secondList) {
            events.add(new Event(s[0], 0));
            events.add(new Event(s[1], 1));
        }
        
        Collections.sort(events, new EventComparator());
        int cnt = 0;
        int l = 0, r = 0;
        List<int[]> lst = new ArrayList<>();
        
        for (Event e : events) {
            if (e.start == 0) {
                cnt++;
                if (cnt == 2) {
                    l = e.time;
                }
            }
            else {
                cnt--;
                if (cnt == 1) {
                    r = e.time;
                    lst.add(new int[]{l, r});
                }
            }
        }
        
        int[][] res = new int[lst.size()][2];
        for (int i = 0; i < lst.size(); i++) {
            res[i] = lst.get(i);
        }
        
        return res;
    }
}

方法2:双指针

时间复杂度:O(m + n) 想法:给第一个数组一个指针i,给第二个数组一个指针j,直接开扫。如果目前i指向的这个整个已经在j指向的那个前面了,那就得把i后移,相似反之情况把j后移。如果这俩指的有交集,那就先记一下交集,然后让目前指向的那个元素结束比较早的指针往后移。因为这个时候它后移,另一个指针指向的那个结束比较晚,这俩还有可能再有交集,否则就完全没可能。如果结束时间相同,俩都后移。比较直观的做法。 代码:

class Solution {
    public int[][] intervalIntersection(int[][] firstList, int[][] secondList) {
        List<int[]> lst = new ArrayList<>();
        int m = firstList.length, n = secondList.length, i = 0, j = 0;
        
        while (i < m && j < n) {
            if (firstList[i][1] < secondList[j][0]) {
                i++;
            }
            else if (firstList[i][0] > secondList[j][1]) {
                j++;
            }
            else {
                lst.add(new int[] {Math.max(firstList[i][0], secondList[j][0]), Math.min(firstList[i][1], secondList[j][1])});
                if (firstList[i][1] < secondList[j][1]) {
                    i++;
                }
                else if (firstList[i][1] > secondList[j][1]) {
                    j++;
                }
                else {
                    i++;
                    j++;
                }
            }
        }
        
        int[][] res = new int[lst.size()][2];
        for (int k = 0; k < lst.size(); k++) {
            res[k] = lst.get(k);
        }
        
        return res;
    }
}

突然发现简书一天之内最多发两篇文章,那以后合并着发

LeetCode 1353

链接:leetcode.com/problems/ma…

方法:优先队列

时间复杂度:O(nlogn) 想法:这个题其实是来自计算机操作系统的一个结论,是CPU调度那一节。这种问题要是想做的尽可能多的话,就是earliest deadline first。实际上我们可以维护一个cur变量,代表我现在考虑的时刻是什么时候,然后每次循环放进去一些现在可以开始参加了的event(那么这里会看到得给events排序),然后用堆PriorityQueue来动态拿结束时间最早的任务。我们for循环,如果说堆不为空的话,每次cur加一,因为堆不为空,那么cur这个时间就可以参加一个event,那么cur+1就可以在下一次循环考虑下一个时刻。但如果堆为空了,直接就置成events[i][0]。然后每次for循环最后把一堆已经不可能再参加的event扔掉。比方说有好几个[3,5]event,在5这个时刻选择了参加其中一个,那么这时候下一次循环需要考虑的时刻就是6,其余的event就永远不可能参加了,那因为我们每次取出结束时间最早的元素,这个放在里面会搞乱整个程序,因此每次for循环结束把这种元素从堆里删掉。 代码:

class Solution {
    public int maxEvents(int[][] events) {
        Arrays.sort(events, (a, b) -> a[0] - b[0]);
        
        Queue<int[]> heap = new PriorityQueue<>((a, b) -> a[1] - b[1]);
        int res = 0, cur = 0, i = 0, n = events.length;
        
        while (i < n || !heap.isEmpty()) {
            if (heap.isEmpty()) {
                cur = events[i][0];
            }
            
            while (i < n && events[i][0] == cur) {
                heap.offer(events[i++]);
            }
            
            res++;
            heap.poll();
            cur++;
            
            while (!heap.isEmpty() && heap.peek()[1] < cur) {
                heap.poll();
            }
        }
        
        return res;
    }
}