LeetCode 815 - Bus Routes


https://leetcode.com/problems/bus-routes/
We have a list of bus routes. Each routes[i] is a bus route that the i-th bus repeats forever. For example if routes[0] = [1, 5, 7], this means that the first bus (0-th indexed) travels in the sequence 1->5->7->1->5->7->1->... forever.
We start at bus stop S (initially not on a bus), and we want to go to bus stop T. Travelling by buses only, what is the least number of buses we must take to reach our destination? Return -1 if it is not possible.
Example:
Input: 
routes = [[1, 2, 7], [3, 6, 7]]
S = 1
T = 6
Output: 2
Explanation: 
The best strategy is take the first bus to the bus stop 7, then take the second bus to the bus stop 6.
Note:
  • 1 <= routes.length <= 500.
  • 1 <= routes[i].length <= 500.
  • 0 <= routes[i][j] < 10 ^ 6

Time Complexity: O(m*n) m: # of buses, n: # of routes
Space complexity: O(m*n + m)
解法:BFS,先对原来的二维数组进行处理,二维数组的每一行代表这辆公交车能到达的站点,用HashMap记录某站点有哪个公交经过。这样处理完以后就知道每一个站点都有哪个公交车经过了。然后用一个queue记录当前站点,对于当前站点的所有经过的公交循环,每个公交又有自己的下一个站点。可以想象成一个图,每一个公交站点 被多少个公交经过,也就是意味着是个中转站,可以连通到另外一个公交上, 因为题目求的是经过公交的数量而不关心经过公交站点的数量,所以在BFS的时候以公交(也就是routes的下标)来扩展。

Solution#2, 可以用stop当作node构建graph,与上面是相同复杂度
ref: https://leetcode.com/problems/bus-routes/discuss/122712/Simple-Java-Solution-using-BFS?page=1
Node是stop,neighbour是bus routes,visited里面存的也是bus route
https://segmentfault.com/a/1190000017229110
    public int numBusesToDestination(int[][] routes, int S, int T) {
        if (S == T) return 0;
        
        //pre-processing: save <stop, List<buses>> for BFS
        Map<Integer, List<Integer>> map = new HashMap<>();
        for (int i = 0; i < routes.length; i++) {
            for (int stop: routes[i]) {
                if (!map.containsKey(stop)) map.put(stop, new ArrayList<>());
                map.get(stop).add(i);
            }
        }
        
        if (!map.containsKey(S) || !map.containsKey(T)) return -1;
        
        Set<Integer> visited = new HashSet<>(); //to store visited routes
        Deque<Integer> queue = new ArrayDeque<>();
        queue.offer(S);
        
        int transitions = 0;
        while (!queue.isEmpty()) {
            int size = queue.size();
            transitions++;
            for (int i = 0; i < size; i++) {
                int curStop = queue.poll();
                List<Integer> buses = map.get(curStop);
                for (int bus: buses) {
                    if (visited.contains(bus)) continue;
                    visited.add(bus);
                    for (int stop: routes[bus]) {
                        if (stop == T) return transitions;
                        else queue.offer(stop);
                    }
                }
            }
        }
        
        return -1;
    }
https://leetcode.com/problems/bus-routes/discuss/122771/C%2B%2BJavaPython-BFS-Solution
The first part loop on routes and record stop to routes mapping in to_route.
The second part is general bfs. Take a stop from queue and find all connected route.
The set seen record all stops visted and we won't check a stop for twice.
We can also use a set to record all routes visted , or just clear a route after visit.
    public int numBusesToDestination(int[][] routes, int S, int T) {
        HashMap<Integer, HashSet<Integer>> to_routes = new HashMap<>();
        for (int i = 0; i < routes.length; ++i)
            for (int j : routes[i]) {
                if (!to_routes.containsKey(j)) to_routes.put(j, new HashSet<Integer>());
                to_routes.get(j).add(i);
            }
        Queue<Point> bfs = new ArrayDeque();
        bfs.offer(new Point(S, 0));
        HashSet<Integer> seen = new HashSet<>();
        seen.add(S);
        while (!bfs.isEmpty()) {
            int stop = bfs.peek().x, bus = bfs.peek().y;
            bfs.poll();
            if (stop == T) return bus;
            for (int route_i : to_routes.get(stop))
                for (int next_stop : routes[route_i])
                    if (!seen.contains(next_stop)) {
                        seen.add(next_stop);
                        bfs.offer(new Point(next_stop, bus + 1));
                    }
        }
        return -1;
    }
https://leetcode.com/problems/bus-routes/discuss/122712/Simple-Java-Solution-using-BFS
For each of the bus stop, we maintain all the buses (bus routes) that go through it. To do that, we use a HashMap, where bus stop number is the key and all the buses (bus routes) that go through it are added to an ArrayList.
We use BFS, where we process elements in a level-wise manner. We add the Start bus stop in the queue. Next, when we enter the while loop, we add all the bus stops that are reachable by all the bus routes that go via the Start. Thus, if we have the input as [[1, 2, 7], [3, 6, 7]] and Start as 6, then upon processing bus stop 6, we would add bus stops 3 and 7.
With this approach, all the bus stops at a given level, are "equal distance" from the start node, in terms of number of buses that need to be changed.
To avoid loops, we also maintain a HashSet that stores the buses that we have already visited.
Note that while in this approach, we use each stop for doing BFS, one could also consider each bus (route) also for BFS.
    public int numBusesToDestination(int[][] routes, int S, int T) {
       HashSet<Integer> visited = new HashSet<>();
       Queue<Integer> q = new LinkedList<>();
       HashMap<Integer, ArrayList<Integer>> map = new HashMap<>();
       int ret = 0; 
        
       if (S==T) return 0; 
        
       for(int i = 0; i < routes.length; i++){
            for(int j = 0; j < routes[i].length; j++){
                ArrayList<Integer> buses = map.getOrDefault(routes[i][j], new ArrayList<>());
                buses.add(i);
                map.put(routes[i][j], buses);                
            }       
        }
                
       q.offer(S); 
       while (!q.isEmpty()) {
           int len = q.size();
           ret++;
           for (int i = 0; i < len; i++) {
               int cur = q.poll();
               ArrayList<Integer> buses = map.get(cur);
               for (int bus: buses) {
                    if (visited.contains(bus)) continue;
                    visited.add(bus);
                    for (int j = 0; j < routes[bus].length; j++) {
                        if (routes[bus][j] == T) return ret;
                        q.offer(routes[bus][j]);  
                   }
               }
           }
        }
        return -1;
    }

https://leetcode.com/articles/bus-routes/
  public int numBusesToDestination(int[][] routes, int S, int T) {
    if (S == T)
      return 0;
    int N = routes.length;

    List<List<Integer>> graph = new ArrayList();
    for (int i = 0; i < N; ++i) {
      Arrays.sort(routes[i]);
      graph.add(new ArrayList());
    }
    Set<Integer> seen = new HashSet();
    Set<Integer> targets = new HashSet();
    Queue<Point> queue = new ArrayDeque();

    // Build the graph. Two buses are connected if
    // they share at least one bus stop.
    for (int i = 0; i < N; ++i)
      for (int j = i + 1; j < N; ++j)
        if (intersect(routes[i], routes[j])) {
          graph.get(i).add(j);
          graph.get(j).add(i);
        }

    // Initialize seen, queue, targets.
    // seen represents whether a node has ever been enqueued to queue.
    // queue handles our breadth first search.
    // targets is the set of goal states we have.
    for (int i = 0; i < N; ++i) {
      if (Arrays.binarySearch(routes[i], S) >= 0) {
        seen.add(i);
        queue.offer(new Point(i, 0));
      }
      if (Arrays.binarySearch(routes[i], T) >= 0)
        targets.add(i);
    }

    while (!queue.isEmpty()) {
      Point info = queue.poll();
      int node = info.x, depth = info.y;
      if (targets.contains(node))
        return depth + 1;
      for (Integer nei : graph.get(node)) {
        if (!seen.contains(nei)) {
          seen.add(nei);
          queue.offer(new Point(nei, depth + 1));
        }
      }
    }

    return -1;
  }

  public boolean intersect(int[] A, int[] B) {
    int i = 0, j = 0;
    while (i < A.length && j < B.length) {
      if (A[i] == B[j])
        return true;
      if (A[i] < B[j])
        i++;
      else
        j++;
    }
    return false;

  }


Solution #1 以bus route为⼀个node, 构建graph O(n * n * l) time, n为route的数量量,l为route的平均长度
    public int numBusesToDestination(int[][] routes, int s, int t) {
        if (s == t) return 0;
         
        Map<Integer, Cluster> graph = new HashMap<>();
        Queue<Integer> source = mergeRoutes(graph, routes, s);
        Set<Integer> visited = new HashSet<>();
        int len = 1;
         
        while (!source.isEmpty()) {
             
            int size = source.size();
            while (size > 0) {
                int top = source.poll();
                 
                size--;
                if (visited.contains(top)) continue;
                visited.add(top);
                Cluster topC = graph.get(top);
                 
                if (topC.elems.contains(t)) return len;
                for (int c : topC.neighbours) {
                    source.add(c);
                }
            }
            len++;
        }
         
        return -1;
    }
     
    private Queue<Integer> mergeRoutes(Map<Integer, Cluster> graph, int[][] routes, int s) {
         
        Queue<Integer> source = new LinkedList<>();
         
        for (int i = 0; i < routes.length; i++) {
            Cluster c = new Cluster(i, routes[i]);
            graph.put(i, c);
             
            for (int elem : routes[i]) {
                if (elem == s) source.add(i);
                     
                for (Map.Entry<Integer, Cluster> entry : graph.entrySet()) {
                    if (entry.getValue().elems.contains(elem)) {
                        entry.getValue().neighbours.add(i);
                        c.neighbours.add(entry.getValue().index);
                    }
                }
            }
        }
        return source;
    }
     
    class Cluster{
        public int index;
        public Set<Integer> elems;
        public Set<Integer> neighbours;
         
        public Cluster(int index, int[] route) {
            this.index = index;
            elems = new HashSet<>();
            for (int i : route) {
                elems.add(i);
            }
             
            neighbours = new HashSet<>();
        }
    }

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