Google – Remove Alarm


Google – Remove Alarm
有一堆Alarm, 每个alarm有三个值,start time, end time和priority。要求是把那些从没有成为过最高优先级的alarm给删除。
比如有这么几个alarms:
Alarm1 (1, 2, 1)
Alarm2 (1, 4, 2)
Alarm3 (3, 5, 3)
Alarm4 (3, 4, 2)
那么比如alarm1和alarm4就是要删除的。因为alarm1和alarm2同时开始,但是第二个优先级高,等第二个结束的时候第一个alarm早就结束了。所以第一个alarm从来没有到过最高优先级。alarm4也是一样。
[Solution]
这道题学会了一种新的算法:scan-line algorithm,中文叫扫描线算法。Leetcode里的the skyline problem使用的也是这种算法。
http://www.jiuzhang.com/qa/339/
思路就是把每个alarm的range拆成两条线,每条线记录一下信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
class Line {
    int time;
    boolean isStart;
    int priority;
    int id;
    Line(int time, boolean isStart, int priority, int id) {
      this.time = time;
      this.isStart = isStart;
      this.priority = priority;
      this.id = id;
    }
  }
  1. 对所有Line按照time进行排序,如果time一样的,priority高的在前,如果priority也一样的,start在前,end在后。
  2. 遍历所有lines,边遍历边维护一个hash map和一个max heap.
    • hash map用来map priority to set of alarm id
    • max heap用来找最高的priority。
    1. 如果当前line是start, 那么把alarm id加入hash table对应priority的set里,并把priority加入max heap
    2. 如果当前line是end, 那么把alarm id从对应priority的set里删除,如果删除它之后对应的set为空了,那么把这个priority分别从hash table和max heap里删除。
    3. 每处理完一条line,都要从maxHeap里取出最大的priority,再到hash table里把该最大priority的alarm id全部mark一遍,表示这些alarm成为最高priority,不用删除。
  3. 最后删除那些没有被mark过的alarm
[Note]
因为这道题涉及到从maxHeap里删除元素,heap的结构是不支持search和delete功能的,所以本质上priority queue的remove方法就是对底层的internal array扫一遍来找到要删除的元素。时间是O(n),如果不对这个细节做特殊处理的话,整个算法的复杂度会变为O(n2)。
上面的连接里提到了一种Hash Heap的数据结构,就是用一个hash table来映射heap里每个元素的对应位置,这样在remove的时候就可以做到O(1)时间。


非常复杂的一道题,算法,思路和数据结构都很新颖。

class Alarm {
  int start;
  int end;
  int priority;
  Alarm(int start, int end, int priority) {
    this.start = start;
    this.end = end;
    this.priority = priority;
  }
}
class Solution {
  public void removeAlarm(List<Alarm> alarms) {
    if (alarms == null || alarms.isEmpty()) {
      return;
    }
    List<Line> Lines = new ArrayList<>();
    for (int i = 0; i < alarms.size(); i++) {
      Alarm alarm = alarms.get(i);
      Lines.add(new Line(alarm.start, true, alarm.priority, i));
      Lines.add(new Line(alarm.end, false, alarm.priority, i));
    }
    Collections.sort(Lines, new Comparator<Line>() {
      public int compare(Line a, Line b) {
        if (a.time == b.time && a.priority == b.priority) {
          return a.isStart? -1 : 1;
        }
        else if (a.time == b.time) {
          return -(a.priority - b.priority);
        }
        return a.time - b.time;
      }
    });
    Map<Integer, Set<Integer>> priorityMap = new HashMap<>();
    PriorityQueue<Integer> maxHeap = new PriorityQueue<>(5, Collections.reverseOrder());
    Set<Integer> mark = new HashSet<>();
    for (Line Line : Lines) {
      if (Line.isStart) {
        if (!priorityMap.containsKey(Line.priority)) {
          priorityMap.put(Line.priority, new HashSet<>());
          maxHeap.offer(Line.priority);
        }
        priorityMap.get(Line.priority).add(Line.id);
      }
      else {
        priorityMap.get(Line.priority).remove(Line.id);
        if (priorityMap.get(Line.priority).isEmpty()) {
          priorityMap.remove(Line.priority);
          maxHeap.remove(Line.priority);
        }
      }
      if (!maxHeap.isEmpty()) {
        int top = maxHeap.peek();
        for (int id : priorityMap.get(top)) {
          mark.add(id);
        }
      }
    }
    for (int i = 0; i < alarms.size(); i++) {
      if (!mark.contains(i)) {
        System.out.println(i);
      }
    }
  }
  private class Line {
    int time;
    boolean isStart;
    int priority;
    int id;
    Line(int time, boolean isStart, int priority, int id) {
      this.time = time;
      this.isStart = isStart;
      this.priority = priority;
      this.id = id;
    }
  }
}
http://www.jiuzhang.com/qa/339/

有一个需要clarify的地方是,如果和其他的alert一起同时成为最高的优先度,这种需要去掉么?
下面的解答基于不需要去掉与其他alarm同时成为最高优先度的那些alarms:
  1. 将起始时间终止,终止时间和对应的优先度以及alarm的id打散。一个alarm会变成两个item:(start_time, alarm_id, priority, is_start=true), (end_time, alarm_id, priority, is_start=false)
  2. 把所有的2N个items排序。按照第一个field time从小到大排序。
  3. 依次访问排序后的每个item
    1. 如果is_start=true,那么 check priority 是否在某个集合中,如果不在的话就create一个entry 给这个priority,将alarm_id添加到该priority的一个list里,表示当前是该priority的alarms有哪些。entry包括两个部分,一个是priority,作为key,第二个是一个list,表示有哪些alarms,作为value。
    2. 如果is_start=false,那么 找到集合中priority对应的entry,然后把alarm_id从里面删除,如果entry里的list空了,就在集合中删除这条entry。
    3. 上面的操作完成后,检查目前集合中priority最高的entry,把这个entry里的alarms都标记为成为过最高优先级的。
  4. 最后再check所有的alarm,看看哪些没有被标记过。
这中间有一个优化需要做的是,需要把list分为已经标记过成为最高优先级的,和没有标记过成为最高优先级的。否则反复标记同一个alarm成为过最高优先级会耗费时间复杂度。 这个list,本身因为需要支持插入和删除的话,那么其实实际上应该是两个hashset。
整体的时间复杂度是(NlogN + NlogP),N为alarms的个数,P为Priority的个数,NlogN是排序的复杂度,NlogP是后面统计处理的时候的复杂度。至于这个集合既需要做key-value的查询,又需要找最大值,那么自然是HashHeap。这种数据机构,我们会在《九章算法强化班》中讲解。
这种算法的名字叫做:扫描线算法。是Google的大爱。
类似的题目是这题,也是Google出过的题:
http://www.lintcode.com/en/problem/building-outline/
Read full article from Google – Remove Alarm

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