LeetCode 759 - Employee Free Time


http://www.cnblogs.com/grandyang/p/8552586.html
We are given a list schedule of employees, which represents the working time for each employee.
Each employee has a list of non-overlapping Intervals, and these intervals are in sorted order.
Return the list of finite intervals representing common, positive-length free time for all employees, also in sorted order.
Example 1:
Input: schedule = [[[1,2],[5,6]],[[1,3]],[[4,10]]]
Output: [[3,4]]
Explanation:
There are a total of three employees, and all common
free time intervals would be [-inf, 1], [3, 4], [10, inf].
We discard any intervals that contain inf as they aren't finite.

Example 2:
Input: schedule = [[[1,3],[6,7]],[[2,4]],[[2,5],[9,12]]]
Output: [[5,6],[7,9]]

(Even though we are representing Intervals in the form [x, y], the objects inside are Intervals, not lists or arrays. For example, schedule[0][0].start = 1, schedule[0][0].end = 2, and schedule[0][0][0] is not defined.)
Also, we wouldn't include intervals like [5, 5] in our answer, as they have zero length.
Note:
  1. schedule and schedule[i] are lists with lengths in range [1, 50].
  2. 0 <= schedule[i].start < schedule[i].end <= 10^8.

题目大意:给你每个员工的日历,让你找出所有员工都有空的时间段。

X. PriorityQueue:
Time Complexity: O(nlogk). k是employee的个数, schedule.size(). n是一共有多少interval.
http://hehejun.blogspot.com/2018/02/leetcodeemployee-free-time.html
此外我们用merge k sorted lists的解法也可以
https://www.cnblogs.com/Dylan-Java-NYC/p/9399311.html
k条已经排好序的链表. 利用minHeap进行merge. 
先把每个表头放在minHeap中. minHeap按照指向的Interval start排序.
poll出来的就是当前最小start的interval. 如果标记的时间比这个interval的start还小就说明出现了断裂也就是空余时间. 
把标记时间增大到这个interval的end, 并且把这个interval所在链表的后一位加入minHeap中.
Time Complexity: O(nlogk). k是employee的个数, schedule.size(). n是一共有多少interval.
Space: O(k).
11     public List<Interval> employeeFreeTime(List<List<Interval>> schedule) {
12         List<Interval> res = new ArrayList<Interval>();
13         PriorityQueue<Node> minHeap = new PriorityQueue<Node>((a,b) -> 
14                                             schedule.get(a.employee).get(a.index).start - schedule.get(b.employee).get(b.index).start);
15         
16         int start = Integer.MAX_VALUE;
17         for(int i = 0; i<schedule.size(); i++){
18             minHeap.add(new Node(i, 0));
19             start = Math.min(start, schedule.get(i).get(0).start);
20         }
21         
22         while(!minHeap.isEmpty()){
23             Node cur = minHeap.poll();
24             if(start < schedule.get(cur.employee).get(cur.index).start){
25                 res.add(new Interval(start, schedule.get(cur.employee).get(cur.index).start));
26             }
27             
28             start = Math.max(start, schedule.get(cur.employee).get(cur.index).end);
29             cur.index++;
30             if(cur.index < schedule.get(cur.employee).size()){
31                 minHeap.add(cur);
32             }
33         }
34         
35         return res;
36     }
39 class Node{
40     int employee;
41     int index;
42     public Node(int employee, int index){
43         this.employee = employee;
44         this.index = index;
45     }
46 }
https://blog.csdn.net/zjucor/article/details/79007431
合并所有的interval,找到空隙的,可以对所有的interval进行一遍排序(按照interval.start,因为合并要按照start的顺序来才是对的),用优先队列可以进一步简化时间复杂度,省去了整体排序的时间


  public List<Interval> employeeFreeTime(final List<List<Interval>> avails) {
    PriorityQueue<int[]> pq = new PriorityQueue<int[]>(50, new Comparator<int[]>() {
      @Override
      public int compare(int[] a1int[] a2) {
        return avails.get(a1[0]).get(a1[1]).start - avails.get(a2[0]).get(a2[1]).start;
      }
    });
    Stack<Intervalst = new Stack<Interval>();

    for (int i = 0; i < avails.size(); i++)
      pq.add(new int[] { i, 0 });

    while (!pq.isEmpty()) {
      int[] tt = pq.remove();
      if (tt[1] + 1 < avails.get(tt[0]).size())
        pq.add(new int[] { tt[0], tt[1] + 1 });
      Interval t = avails.get(tt[0]).get(tt[1]);
      if (st.isEmpty()) {
        st.add(t);
      else {
        Interval top = st.pop();
        if (top.end >= t.start) {
          st.push(new Interval(top.start, Math.max(top.end, t.end)));
        else {
          st.push(top);
          st.push(t);
        }
      }
    }

    List<Intervalret = new ArrayList<Interval>();
    LinkedList<Intervalt = new LinkedList<Interval>();
    while (!st.isEmpty())
      t.add(0, st.pop());
    for (int i = 0; i < t.size() - 1; i++)
      ret.add(new Interval(t.get(i).end, t.get(i + 1).start));
    return ret;



  }

X. TreeMap: O(nlogn)
我们再来看一种解法,这种解法挺巧妙的,我们使用TreeMap建立一个位置和其出现次数之间的映射,对于起始位置,进行正累加,对于结束位置,进行负累加。由于TreeMap具有自动排序的功能,所以我们进行遍历的时候,就是从小到大进行遍历的。定义一个变量cnt,初始化为0,我们对于每个遍历到的数,都加上其在TreeMap中的映射值,即该数字出现的次数,起始位置的话就会加正数,结束位置就是加负数。开始的时候,第一个数字一定是个起始位置,那么cnt就是正数,那么接下来cnt就有可能加上正数,或者减去一个负数,我们想,如果第一个区间和第二个区间没有交集的话,那么接下来遇到的数字就是第一个区间的结束位置,所以会减去1,这样此时cnt就为0了,这说明一定会有中间区域存在,所以我们首先把第一个区间当前起始位置,结束位置暂时放上0,组成一个区间放到结果res中,这样我们在遍历到下一个区间的时候更新结果res中最后一个区间的结束位置。语言描述难免太干巴巴的,我们拿题目中的例1来说明,建立好的TreeMap如下所示:
1 -> 2
2 -> -1
3 -> -1
4 -> 1
5 -> 1
6 -> -1
10 -> -1
那么开始遍历这所有的映射对,cnt首先为2,然后往后遍历下一个映射对2 -> -1,此时cnt为1了,不进行其他操作,再往下遍历,下一个映射对3 -> -1,此时cnt为0了,说明后面将会出现断层了,我们将(3, 0)先存入结果res中。然后遍历到4 -> 1时,cnt为1,此时将结果res中的(3, 0)更新为 (3, 4)。然后到5 -> 1,此时cnt为2,不进行其他操作,然后到6 -> -1,此时cnt为1,不进行其他操作,然后到10 -> -1,此时cnt为0,将(10, 0)加入结果res中。由于后面再没有任何区间了,所以res最后一个区间不会再被更新了,我们应该将其移出结果res,因为题目中限定了区间不能为无穷,参见代码如下:
    vector<Interval> employeeFreeTime(vector<vector<Interval>>& schedule) {
        vector<Interval> res;
        map<int, int> m;
        int cnt = 0;
        for (auto employee : schedule) {
            for (Interval i : employee) {
                ++m[i.start];
                --m[i.end];
            }
        }
        for (auto a : m) {
            cnt += a.second;
            if (!cnt) res.push_back(Interval(a.first, 0));
            if (cnt && !res.empty() && !res.back().end) res.back().end = a.first;
        }
        if (!res.empty()) res.pop_back();
        return res;
    }

X. Sort Intervals
    vector<Interval> employeeFreeTime(vector<vector<Interval>>& schedule) {
      vector<Interval> all;
      for (const auto intervals : schedule)
        all.insert(all.end(), intervals.begin(), intervals.end());
      std::sort(all.begin(), all.end(),
                [](const Interval& a, const Interval& b){
                  return a.start < b.start;
                });
      vector<Interval> ans;
      int end = all.front().end;
      for (const Interval& busy : all) {
        if (busy.start > end)
          ans.emplace_back(end, busy.start);  
        end = max(end, busy.end);
      }
      return ans;
    }

这道题和之前那道Merge Intervals基本没有太大的区别,那道题是求合并后的区间,这道题求合并后区间中间不相连的区间。那么只要我们合并好了区间,就很容易做了。那么我么首先应该给所有的区间排个序,按照起始位置从小到大来排。因为我们总不可能一会处理前面的,一会处理后面的区间。排好序以后,我们先取出第一个区间赋给t,然后开始遍历所有的区间内所有的区间,如果t的结束位置小于当前遍历到的区间i的起始位置,说明二者没有交集,那么把不相交的部分加入结果res中,然后把当前区间i赋值给t;否则如果区间t和区间i有交集,那么我们更新t的结束位置为二者中的较大值,因为按顺序遍历区间的时候,区间t的结束位置是比较的基准,越大越容易和后面的区间进行合并
    vector<Interval> employeeFreeTime(vector<vector<Interval>>& schedule) {
        vector<Interval> res, v;
        for (auto a : schedule) {
            v.insert(v.end(), a.begin(), a.end());
        }
        sort(v.begin(), v.end(), [](Interval &a, Interval &b) {return a.start < b.start;});
        Interval t = v[0];
        for (Interval i : v) {
            if (t.end < i.start) {
                res.push_back(Interval(t.end, i.start));
                t = i;
            } else {
                t = (t.end < i.end) ? i : t;
            }
        }
        return res;
    }
    public List<Interval> employeeFreeTime(List<List<Interval>> schedule) {
        List<Interval> res = new ArrayList<>();
        List<Interval> times = new ArrayList<>();
        for (List<Interval> list: schedule) {
            times.addAll(list);
        }
        Collections.sort(times, ((i1, i2)->i1.start-i2.start));
        Interval pre = times.get(0);
        for (int i = 1; i < times.size(); i++) {
            Interval cur = times.get(i);
            if (cur.start <= pre.end) {
                pre.end = cur.end > pre.end ? cur.end : pre.end;
            } else {
                res.add(new Interval(pre.end, cur.start));
                pre = cur;
            }    
        }
        return res;
    }
X. https://blog.csdn.net/magicbean2/article/details/79569830
我们首先将所有员工的工作时段进行合并。然后从合并后的intervals中找出有限的空余时段即可。整个算法的时间复杂度是O(nlogn),空间复杂度是O(n),其中n是所有员工的工作时段的总数。
    vector<Interval> employeeFreeTime(vector<vector<Interval>>& schedule) {
        vector<Interval> intervals, result, ans;
        for (int i = 0; i < schedule.size(); ++i) {
            for (int j = 0; j < schedule[i].size(); ++j) {
                intervals.push_back(schedule[i][j]);
            }
        }
        sort(intervals.begin(), intervals.end(), [](const Interval &a, const Interval &b) {
            return a.start < b.start || (a.start == b.start && a.end < b.end); });
        result.push_back(intervals[0]);
        for (int i = 1; i < intervals.size(); ++i) {
            if (intervals[i].start <= result.back().end) {
                result.back().end = max(result.back().end, intervals[i].end);
            }
            else {
                result.push_back(intervals[i]);
            }
        }
        for (int i = 0; i + 1 < result.size(); ++i) {
            if (result[i].end < result[i + 1].start) {
                ans.push_back(Interval(result[i].end, result[i + 1].start));
            }
        }
        return ans;
    }

X. Videos
花花酱 LeetCode 759. Employee Free Time - 刷题找工作 EP 154

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts