Showing posts with label bfs. Show all posts
Showing posts with label bfs. Show all posts

Wednesday, February 27, 2019

934. Shortest Bridge

934. Shortest Bridge
In a given 2D binary array A, there are two islands.  (An island is a 4-directionally connected group of 1s not connected to any other 1s.)
Now, we may change 0s to 1s so as to connect the two islands together to form 1 island.
Return the smallest number of 0s that must be flipped.  (It is guaranteed that the answer is at least 1.)

Example 1:
Input: [[0,1],[1,0]]
Output: 1
Example 2:
Input: [[0,1,0],[0,0,0],[0,0,1]]
Output: 2
Example 3:
Input: [[1,1,1,1,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,0,1],[1,1,1,1,1]]
Output: 1

Note:
  1. 1 <= A.length = A[0].length <= 100
  2. A[i][j] == 0 or A[i][j] == 1
-------------------
BFS
先标记出一个岛,然后做BFS直到碰到另一个岛
注意dis的初始值是 -1
class Solution {
    public int shortestBridge(int[][] arr) {

        Queue<int[]> que = new LinkedList<>();

        for (int i = 0; i < arr.length; i++) {
            boolean f = false;
            for (int j = 0; j < arr[0].length; j++) {
                if (arr[i][j] == 1) {
                    dfs(arr, i, j, que);
                    f = true;
                    break;
                }
            }
            if (f) break;
        }

        int dis = -1;
        while (!que.isEmpty()) {
            
            for (int size = que.size(); size > 0; size--) {
                int[] top = que.poll();
                int i = top[0], j = top[1];
                if (i < 0 || j < 0 || i >= arr.length || j >= arr[0].length || arr[i][j] == 3) continue;
                if (arr[i][j] == 1) return dis;
                arr[i][j] = 3;
                que.add(new int[]{i + 1, j});
                que.add(new int[]{i, j + 1});
                que.add(new int[]{i - 1, j});
                que.add(new int[]{i, j - 1});
            }
            dis++;
        }


        return 0;
    }

    private void dfs(int[][] arr, int i, int j, Queue<int[]> que) {
        if (i < 0 || j < 0 || i >= arr.length || j >= arr[0].length || arr[i][j] == 0 || arr[i][j] == 2) return;

        arr[i][j] = 2;
        que.add(new int[]{i, j});
        dfs(arr, i + 1, j, que);
        dfs(arr, i - 1, j, que);
        dfs(arr, i, j + 1, que);
        dfs(arr, i, j - 1, que);
    }
}

Saturday, January 26, 2019

909. Snakes and Ladders

909. Snakes and Ladders
On an N x N board, the numbers from 1 to N*N are written boustrophedonically starting from the bottom left of the board, and alternating direction each row.  For example, for a 6 x 6 board, the numbers are written as follows:

You start on square 1 of the board (which is always in the last row and first column).  Each move, starting from square x, consists of the following:
  • You choose a destination square S with number x+1, x+2, x+3, x+4, x+5, or x+6, provided this number is <= N*N.
    • (This choice simulates the result of a standard 6-sided die roll: ie., there are always at most 6 destinations.)
  • If S has a snake or ladder, you move to the destination of that snake or ladder.  Otherwise, you move to S.
A board square on row r and column c has a "snake or ladder" if board[r][c] != -1.  The destination of that snake or ladder is board[r][c].
Note that you only take a snake or ladder at most once per move: if the destination to a snake or ladder is the start of another snake or ladder, you do not continue moving.  (For example, if the board is `[[4,-1],[-1,3]]`, and on the first move your destination square is `2`, then you finish your first move at `3`, because you do not continue moving to `4`.)
Return the least number of moves required to reach square N*N.  If it is not possible, return -1.
Example 1:
Input: [
[-1,-1,-1,-1,-1,-1],
[-1,-1,-1,-1,-1,-1],
[-1,-1,-1,-1,-1,-1],
[-1,35,-1,-1,13,-1],
[-1,-1,-1,-1,-1,-1],
[-1,15,-1,-1,-1,-1]]
Output: 4
Explanation: 
At the beginning, you start at square 1 [at row 5, column 0].
You decide to move to square 2, and must take the ladder to square 15.
You then decide to move to square 17 (row 3, column 5), and must take the snake to square 13.
You then decide to move to square 14, and must take the ladder to square 35.
You then decide to move to square 36, ending the game.
It can be shown that you need at least 4 moves to reach the N*N-th square, so the answer is 4.
Note:
  1. 2 <= board.length = board[0].length <= 20
  2. board[i][j] is between 1 and N*N or is equal to -1.
  3. The board square with number 1 has no snake or ladder.
  4. The board square with number N*N has no snake or ladder.
--------------------
一开始想太复杂了。找最短路径,简单的bfs就能搞定,不用dp。其中一些点会往回走,不用担心,visitted[] 数组就可以搞定

1. 每次都直接把board上的value给读进去,这样就可以处理每次最多只能爬一次楼梯
2. 满足1的条件下,如果是楼梯的话,只能爬楼梯,不能掷骰子

class Solution {
    public int snakesAndLadders(int[][] board) {
        int n = board.length;
        Queue<Integer> que = new LinkedList<>();
        boolean[] visited = new boolean[n * n + 1];
        visited[1] = true; 
        que.add(1);    
        
        int step = 0;
        while (!que.isEmpty()) {
            int len = que.size();
            for (;len > 0; len--) {
                int cur = que.poll();
                if (cur == n * n) return step;
                
                for (int i = 1; i <= 6; i++) {
                    int next = cur + i;
                    if (next > n * n) continue;
                    int nextValue = getValue(board, next);
                    
                    if (nextValue != -1) next = nextValue;
                    if (visited[next]) continue;
                    que.add(next);
                    visited[next] = true;
                }
            }
            
            step++;
        }
        
        return -1;
    }
    
    private int getValue(int[][] board, int i) {
        int n = board.length;
        int r = (n - 1) - (i - 1) / n;
        int c = 0;
        if ((i - 1) / n % 2 == 0) {
            c = (i - 1) % n;
        }else {
            c = n - 1 - (i - 1) % n;
        }
        
        return board[r][c];
    }
}

Friday, September 14, 2018

505. The Maze II

505. The Maze II
There is a ball in a maze with empty spaces and walls. The ball can go through empty spaces by rolling up, down, left or right, but it won't stop rolling until hitting a wall. When the ball stops, it could choose the next direction.
Given the ball's start position, the destination and the maze, find the shortest distance for the ball to stop at the destination. The distance is defined by the number of empty spaces traveled by the ball from the start position (excluded) to the destination (included). If the ball cannot stop at the destination, return -1.
The maze is represented by a binary 2D array. 1 means the wall and 0 means the empty space. You may assume that the borders of the maze are all walls. The start and destination coordinates are represented by row and column indexes.
Example 1
Input 1: a maze represented by a 2D array

0 0 1 0 0
0 0 0 0 0
0 0 0 1 0
1 1 0 1 1
0 0 0 0 0

Input 2: start coordinate (rowStart, colStart) = (0, 4)
Input 3: destination coordinate (rowDest, colDest) = (4, 4)

Output: 12
Explanation: One shortest way is : left -> down -> left -> down -> right -> down -> right.
             The total distance is 1 + 1 + 3 + 1 + 2 + 2 + 2 = 12.

Example 2
Input 1: a maze represented by a 2D array

0 0 1 0 0
0 0 0 0 0
0 0 0 1 0
1 1 0 1 1
0 0 0 0 0

Input 2: start coordinate (rowStart, colStart) = (0, 4)
Input 3: destination coordinate (rowDest, colDest) = (3, 2)

Output: -1
Explanation: There is no way for the ball to stop at the destination.

Note:
  1. There is only one ball and one destination in the maze.
  2. Both the ball and the destination exist on an empty space, and they will not be at the same position initially.
  3. The given maze does not contain border (like the red rectangle in the example pictures), but you could assume the border of the maze are all walls.
  4. The maze contains at least 2 empty spaces, and both the width and height of the maze won't exceed 100.
------------------
这题其实是一个weighted grahp,vertex是每一个靠墙的点,edge weight是每个vertex之间的距离。所以搜索的方法有dfs,bfs跟dijkstra。复杂度为 (|E| + |V|) * K,K为在每个vertex上的花费

Solution #1, 在Maze I的基础上进行的修改。
1. 因为每一步走的距离都是不等的,所以得保持另一个2d array来记录当前坐标的距离
2. 可以不用预先把记录距离的2d array填满,但是那种算法oj内存溢出,很奇怪
Worst complexity是O((m * n)^2),

class Solution {
    public int shortestDistance(int[][] maze, int[] start, int[] destination) {
        Queue<int[]> que = new LinkedList<>();
        que.add(start);
        int[][] dirs = {{1,0},{-1,0},{0,1},{0,-1}};
        int[][] dis = new int[maze.length][maze[0].length];
        for (int[] row: dis)
            Arrays.fill(row, Integer.MAX_VALUE);
        dis[start[0]][start[1]] = 0;
        
        while (!que.isEmpty()) {
            int[] pos = que.poll();
            
            for (int[] dir : dirs) {
                int i = 0;
                while (pos[0] + dir[0] * i >= 0 && pos[0] + dir[0] * i < maze.length
                      && pos[1] + dir[1] * i >= 0 && pos[1] + dir[1] * i < maze[0].length
                      && maze[pos[0] + dir[0] * i][pos[1] + dir[1] * i] == 0) {
                    i++;
                }
                i--;
                
                if (dis[pos[0] + dir[0] * i][pos[1] + dir[1] * i] > dis[pos[0]][pos[1]] + i) {
                    dis[pos[0] + dir[0] * i][pos[1] + dir[1] * i] = dis[pos[0]][pos[1]] + i;
                    int[] next = new int[]{pos[0] + dir[0] * i, pos[1] + dir[1] * i};
                    que.add(next);
                }
            }
        }
        
        return dis[destination[0]][destination[1]] == Integer.MAX_VALUE ? -1 : dis[destination[0]][destination[1]];
    }
}

Solution #2, Dijkastra
O(m * n * log(m * n)), queue的大小为 m * n, 每次搜索为lg

下面的实现方式有点问题。检查destination应该在刚刚从queue里出来的时候
class Solution {
    public int shortestDistance(int[][] maze, int[] start, int[] destination) {
        int[][] dirs = {{1,0},{-1,0},{0,1},{0,-1}};
        int[][] dis = new int[maze.length][maze[0].length];
        
        PriorityQueue<int[]> que = new PriorityQueue<>((a, b) -> a[2] - b[2]);
        que.add(new int[]{start[0], start[1], 0});
        for (int[] row: dis)
            Arrays.fill(row, Integer.MAX_VALUE);
        dis[start[0]][start[1]] = 0;

        while (!que.isEmpty()) {
            int[] pos = que.poll();
            
            for (int[] dir : dirs) {
                int i = 0;
                    
                while (pos[0] + dir[0] * i >= 0 && pos[0] + dir[0] * i < maze.length
                      && pos[1] + dir[1] * i >= 0 && pos[1] + dir[1] * i < maze[0].length
                      && maze[pos[0] + dir[0] * i][pos[1] + dir[1] * i] == 0) {
                    i++;
                }
                i--;
                
                int row = pos[0] + dir[0] * i;
                int col = pos[1] + dir[1] * i;
                
                if (destination[0] == row && destination[1] == col) return pos[2] + i;
                if (dis[row][col] > dis[pos[0]][pos[1]] + i) {
                    
                    dis[row][col] = dis[pos[0]][pos[1]] + i;
                    int[] next = new int[]{ row, col, pos[2] + i};    
                    que.add(next);
                }
            }
        }
        
        return -1;
    }
}

Thursday, September 13, 2018

490. The Maze

490. The Maze
There is a ball in a maze with empty spaces and walls. The ball can go through empty spaces by rolling up, down, left or right, but it won't stop rolling until hitting a wall. When the ball stops, it could choose the next direction.
Given the ball's start position, the destination and the maze, determine whether the ball could stop at the destination.
The maze is represented by a binary 2D array. 1 means the wall and 0 means the empty space. You may assume that the borders of the maze are all walls. The start and destination coordinates are represented by row and column indexes.
Example 1
Input 1: a maze represented by a 2D array

0 0 1 0 0
0 0 0 0 0
0 0 0 1 0
1 1 0 1 1
0 0 0 0 0

Input 2: start coordinate (rowStart, colStart) = (0, 4)
Input 3: destination coordinate (rowDest, colDest) = (4, 4)

Output: true
Explanation: One possible way is : left -> down -> left -> down -> right -> down -> right.

Example 2
Input 1: a maze represented by a 2D array

0 0 1 0 0
0 0 0 0 0
0 0 0 1 0
1 1 0 1 1
0 0 0 0 0

Input 2: start coordinate (rowStart, colStart) = (0, 4)
Input 3: destination coordinate (rowDest, colDest) = (3, 2)

Output: false
Explanation: There is no way for the ball to stop at the destination.

Note:
  1. There is only one ball and one destination in the maze.
  2. Both the ball and the destination exist on an empty space, and they will not be at the same position initially.
  3. The given maze does not contain border (like the red rectangle in the example pictures), but you could assume the border of the maze are all walls.
  4. The maze contains at least 2 empty spaces, and both the width and height of the maze won't exceed 100.
---------------------
Solution #1, DFS. 这个其实也不用backtracking
比正常的DFS要多一些步骤:
1. 记录走的方向,
2. 每个方向都需要visited信息
3. 检查撞墙
4. 如果不是墙,继续当前方向

O(m * n), 最坏情况每一个格子都走一次

class Solution {
    public boolean hasPath(int[][] maze, int[] start, int[] destination) {
        int m = maze.length, n = maze[0].length;
        boolean[][][] visited = new boolean[m][n][5];
        
        return dfs(maze, destination, visited, start[0] - 1, start[1], 1) ||
            dfs(maze, destination, visited, start[0], start[1] + 1, 2) ||
            dfs(maze, destination, visited, start[0] + 1, start[1], 3) ||
            dfs(maze, destination, visited, start[0], start[1] - 1, 4);
    }
    
    private boolean dfs(int[][] maze, int[] destination, boolean[][][] visited, int row, int col, int dir) {
        if (row < 0 || row >= maze.length || col < 0 || col >= maze[0].length 
            || visited[row][col][dir] || maze[row][col] == 1) return false;
        
        visited[row][col][dir] = true;
        if ((dir == 1 && (row == 0 || maze[row - 1][col] == 1)) || 
           (dir == 3 && (row == maze.length - 1 || maze[row + 1][col] == 1))) {
            
            if (destination[0] == row && destination[1] == col) return true;
            return dfs(maze, destination, visited, row, col - 1, 4) || dfs(maze, destination, visited, row, col + 1, 2); 
        } 
        
        if ((dir == 2 && (col == maze[0].length - 1 || maze[row][col + 1] == 1)) || 
           (dir == 4 && (col == 0 || maze[row][col - 1] == 1))) {
            
            if (destination[0] == row && destination[1] == col) return true;
            return dfs(maze, destination, visited, row - 1, col, 1) || dfs(maze, destination, visited, row + 1, col, 3); 
        }
        
        boolean flag = false;
        if (dir == 1) flag = dfs(maze, destination, visited, row - 1, col, 1);
        if (dir == 2) flag = dfs(maze, destination, visited, row, col + 1, 2);
        if (dir == 3) flag = dfs(maze, destination, visited, row + 1, col, 3); 
        if (dir == 4) flag = dfs(maze, destination, visited, row, col - 1, 4); 
        
        if (flag) return true;
        visited[row][col][dir] = false;
        return false;
    }
}

DFS,在每一层递归里一直走,直到碰到墙。这是对Solution #1的简化
这里不用backtracking,因为每次遇到墙之后情况都会往4个方向尝试走。

class Solution {

    public boolean hasPath(int[][] maze, int[] start, int[] destination) {
        int m = maze.length, n = maze[0].length;
        boolean[][] visited = new boolean[m][n];
        int[][] dirs = {{-1,0}, {1,0}, {0,1},{0,-1}};
        
        return dfs(maze, destination, visited, start[0], start[1], dirs);
    }
    
    private boolean dfs(int[][] maze, int[] destination, boolean[][] visited, int row, int col, int[][] dirs) {
        if (visited[row][col]) return false;
        if (destination[0] == row && destination[1] == col) return true;
        visited[row][col] = true;
        
        for (int[] dir : dirs) {
            int i = 1;
            while (row + dir[0] * i >= 0 && row + dir[0] * i < maze.length 
                   && col + dir[1] * i >= 0 && col + dir[1] * i < maze[0].length 
                   && maze[row + dir[0] * i][col + dir[1] * i] != 1) {
                
                i++;
            }
            i--;
            if (dfs(maze, destination, visited, row + dir[0] * i, col + dir[1] * i, dirs)) return true;
        }
                
        // visited[row][col] = true;
        return false;
    }
}

Solution #3, BFS
class Solution {
    
    public boolean hasPath(int[][] maze, int[] start, int[] destination) {
        Queue<int[]> que = new LinkedList<>();
        que.add(start);
        int[][] dirs = {{1,0},{-1,0},{0,1},{0,-1}};
        boolean[][] visited = new boolean[maze.length][maze[0].length];
        
        while (!que.isEmpty()) {
            int[] pos = que.poll();
            if (pos[0] == destination[0] && pos[1] == destination[1]) return true;
            if (maze[pos[0]][pos[1]] == 1 || visited[pos[0]][pos[1]]) continue;
            visited[pos[0]][pos[1]] = true;
            
            for (int[] dir : dirs) {
                int i = 0;
                while (pos[0] + dir[0] * i >= 0 && pos[0] + dir[0] * i < maze.length
                      && pos[1] + dir[1] * i >= 0 && pos[1] + dir[1] * i < maze[0].length
                      && maze[pos[0] + dir[0] * i][pos[1] + dir[1] * i] == 0) {
                    i++;
                }
                i--;
                int[] next = {pos[0] + dir[0] * i, pos[1] + dir[1] * i};
                que.add(next);
            }
        }
        
        return false;
    }
}

Saturday, August 11, 2018

317. Shortest Distance from All Buildings

317. Shortest Distance from All Buildings
You want to build a house on an empty land which reaches all buildings in the shortest amount of distance. You can only move up, down, left and right. You are given a 2D grid of values 0, 1 or 2, where:
  • Each 0 marks an empty land which you can pass by freely.
  • Each 1 marks a building which you cannot pass through.
  • Each 2 marks an obstacle which you cannot pass through.
Example:
Input: [[1,0,2,0,1],[0,0,0,0,0],[0,0,1,0,0]]

1 - 0 - 2 - 0 - 1
|   |   |   |   |
0 - 0 - 0 - 0 - 0
|   |   |   |   |
0 - 0 - 1 - 0 - 0

Output: 7 

Explanation: Given three buildings at (0,0), (0,4), (2,2), and an obstacle at (0,2),
             the point (1,2) is an ideal empty land to build a house, as the total 
             travel distance of 3+3+1=7 is minimal. So return 7.
Note:
There will be at least one building. If it is not possible to build such house according to the above rules, return -1.
--------------------------------------
难道在有障碍,所以最后选择了brute force, 从每一个building出发做bfs,把所有点的结果加起来找一个最小值。O(k * m * n),k为building的个数,m、n为长宽
隐藏的一个附加条件是,从最后的点必须能走到所有的building,所有额外用了一个参数来记录当前处理过的building的个数,每一次bfs都只尝试之前已经被走过的点。
class Solution {
    public int shortestDistance(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        
        int[][] rt = new int[m][n];
        
        int building = 1;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 1) {
                    building--;
                    bfs(i, j, rt, grid, building);
                }
            }
        }

        return findTheShortest(rt, grid, building - 1);
    }
    
    private int findTheShortest(int[][] rt, int[][] grid, int building) {
        int shortest = Integer.MAX_VALUE;
        boolean found = false;

        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == building) {
                    shortest = Math.min(rt[i][j], shortest);
                    found = true;
                }
            }
        }
        
        return found ? shortest : -1;
    }
    
    private void bfs(int row, int col, int[][] rt, int[][] grid, int building) {
        int m = grid.length;
        int n = grid[0].length;
        boolean[][] visited = new boolean[m][n];
        Queue<Tuple> que = new LinkedList<>();
        que.add(new Tuple(row, col, 0));
        grid[row][col] = building;
        
        while (!que.isEmpty()) {
            Tuple top = que.poll();

            if (isNotValid(top, m, n, grid, visited, building)) {
                continue;
            }
            
            rt[top.row][top.col] += top.dis;
            visited[top.row][top.col] = true;
            grid[top.row][top.col] = building - 1;
            que.add(new Tuple(top.row + 1, top.col, top.dis + 1));
            que.add(new Tuple(top.row, top.col + 1, top.dis + 1));
            que.add(new Tuple(top.row - 1, top.col, top.dis + 1));
            que.add(new Tuple(top.row, top.col - 1, top.dis + 1));
        }
        
        grid[row][col] = 1;
    }
    
    private boolean isNotValid(Tuple t, int m, int n, int[][] grid, boolean[][] visited, int building) {
        int i = t.row, j = t.col;

        return i < 0 || i >= m || j < 0 || j >= n || visited[i][j] || grid[i][j] != building;
    }
}

class Tuple{
    public int row;
    public int col;
    public int dis;
    public Tuple(int row, int col, int dis) {
        this.row = row;
        this.col = col;
        this.dis = dis;
    }
}

Saturday, July 21, 2018

286. Walls and Gates

Walls and Gates
You are given a m x n 2D grid initialized with these three possible values.
  1. -1 - A wall or an obstacle.
  2. 0 - A gate.
  3. INF - Infinity means an empty room. We use the value 231 - 1 = 2147483647 to represent INF as you may assume that the distance to a gate is less than 2147483647.
Fill each empty room with the distance to its nearest gate. If it is impossible to reach a gate, it should be filled with INF.
Example: 
Given the 2D grid:
INF  -1  0  INF
INF INF INF  -1
INF  -1 INF  -1
  0  -1 INF INF
After running your function, the 2D grid should be:
  3  -1   0   1
  2   2   1  -1
  1  -1   2  -1
  0  -1   3   4

------------------------------
典型的BFS,注意的是需要从所有0的位置同时开始走
O(m * n), m n 为2维数组的长宽。因为一个INF的点最多只被走一次
class Solution {

    public void wallsAndGates(int[][] rooms) {
        Queue<Pair> que = getQueue(rooms);
        
        fillRooms(rooms, que);
    }
    
    private void fillRooms(int[][] rooms, Queue<Pair> que) {
        
        int[][] coord = {{1,0}, {-1,0}, {0,1}, {0,-1}};
        
        while (!que.isEmpty()) {
            
            Pair top = que.poll();
            for (int[] arr : coord) {
                int r = top.row + arr[0];
                int c = top.col + arr[1];
                
                if (r >= 0 && r < rooms.length && c >= 0 && c < rooms[0].length
                   && rooms[r][c] == 2147483647) {
                    rooms[r][c] = rooms[top.row][top.col] + 1;
                    que.add(new Pair(r, c));
                }
            }
        }
    }
    
    private Queue<Pair> getQueue(int[][] rooms) {
        Queue<Pair> que = new LinkedList<>();
        
        for (int i = 0; i < rooms.length; i++) {
            for (int j = 0; j < rooms[0].length; j++) {
                if (rooms[i][j] == 0) {
                    que.add(new Pair(i, j));
                }
            }
        }
        
        return que;
    }
}

class Pair{
    public int row;
    public int col;
    public Pair(int row, int col) {
        this.row = row;
        this.col = col;
    }
}

Friday, June 12, 2015

Day 106, ##, Course Schedule, Implement Trie (Prefix Tree)

Course Schedule
There are a total of n courses you have to take, labeled from 0 to n - 1.
Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]
Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?
For example:
2, [[1,0]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.
2, [[1,0],[0,1]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible.
Note:
The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
Hints:
  1. This problem is equivalent to finding if a cycle exists in a directed graph. If a cycle exists, no topological ordering exists and therefore it will be impossible to take all courses.
  2. Topological Sort via DFS - A great video tutorial (21 minutes) on Coursera explaining the basic concepts of Topological Sort.
  3. Topological sort could also be done via BFS.
-------------------------------------------------------------
重点:缺乏知识点,topological ordering的BFS做法https://en.wikipedia.org/wiki/Topological_sorting#Algorithms
Detect if there is a cycle in directed graph,
BFS
class Solution {
public:
    bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector<vector<int> > edges(numCourses);
        vector<int> inDegree(numCourses,0);
        queue<int> que;
         
        for (int i = 0; i < prerequisites.size(); i++) {
            edges[prerequisites[i].second].push_back(prerequisites[i].first);
            inDegree[prerequisites[i].first]++;
        }
        
        for (int i = 0; i < numCourses; i++) {
            if (inDegree[i] == 0) {
                que.push(i);
            }
        }
        
        while (!que.empty()) {
            int current = que.front();
            que.pop();
            for (int i = 0; i < edges[current].size(); i++) {
                inDegree[edges[current][i]]--;
                if (inDegree[edges[current][i]] == 0) {
                    que.push(edges[current][i]);
                }
            }
        }
        
        for (int i = 0; i < numCourses; i++) {
            if (inDegree[i] != 0) {
                return false;
            }
        }
        
        return true;
    }
};

DFS
class Solution {
public:
    bool dfs(vector<vector<int> > &edges, vector<int> &visit, int point) {
        if (visit[point] == -1) return false;
        if (visit[point] == 1) return true;
        
        visit[point] = -1;
        for (int i = 0; i < edges[point].size(); i++) {
            if (!dfs(edges,visit,edges[point][i])) {
                return false;
            }
        }
        visit[point] = 1;
        return true;
    }

    bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector<int> visit(numCourses,0);
        vector<vector<int> > edges(numCourses);
        
        for (int i = 0; i < prerequisites.size(); i++) {
            edges[prerequisites[i].second].push_back(prerequisites[i].first);
        }
        
        for (int i = 0; i < numCourses; i++) {
            if (!dfs(edges,visit,i)) return false;
        }
        
        return true;
    }
};

Java, updated on Sep-29th-2018
class Solution {
    
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        List<List<Integer>> graph = builtGraph(numCourses, prerequisites);
        int[] visited = new int[numCourses];
        
        for (int i = 0; i < numCourses; i++) {
            if (!dfs(graph, i, visited)) return false;
        }
        
        return true;
    }
    
    private boolean dfs(List<List<Integer>> graph, int num, int[] visited) {
        if (visited[num] == 1) return true;
        if (visited[num] == -1) return false;
        
        visited[num] = -1;
        for (int nei : graph.get(num)) {
            if (!dfs(graph, nei, visited)) return false;
        }
        
        visited[num] = 1;
        return true;
    }
    
    private List<List<Integer>> builtGraph(int numCourses, int[][] prerequisites) {
        List<List<Integer>> rt = new ArrayList<>();
        for (int i = 0; i < numCourses; i++) {
            rt.add(new ArrayList<>());
        }
        
        for (int[] edge : prerequisites) {
            rt.get(edge[1]).add(edge[0]);
        }
        
        return rt;
    }

}

BFS, Java
O(n), n是edge的数量,复杂度跟DFS一样
class Solution {
    
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        List<List<Integer>> rt = new ArrayList<>();
        int[] inEdges = new int[numCourses];
        for (int i = 0; i < numCourses; i++) {
            rt.add(new ArrayList<>());
        }
        
        for (int[] edge : prerequisites) {
            rt.get(edge[1]).add(edge[0]);
            inEdges[edge[0]]++;
        }
        
        Queue<Integer> que = new LinkedList<>();
        int count = 0;
        for (int i = 0; i < numCourses; i++) {
            if (inEdges[i] == 0) {
                que.add(i);
            }
        }
        
        while (!que.isEmpty()) {
            int top = que.poll();
            for (int i : rt.get(top)) {
                inEdges[i]--;
                count++;
                if (inEdges[i] == 0) {
                    que.add(i);
                }
            }
        }
        
        return count == prerequisites.length;
    }
}

Implement Trie (Prefix Tree)
Implement a trie with insert, search, and startsWith methods.
Note:
You may assume that all inputs are consist of lowercase letters a-z.
---------------------------------------------
在判断terminal上代码可以更简化
class TrieNode {
public:
    
    // Initialize your data structure here.
    TrieNode() {
        next = vector<TrieNode*>(26,NULL);
        terminal = false;
    }

    char value;
    vector<TrieNode*> next;
    bool terminal;
};

class Trie {
public:
    Trie() {
        root = new TrieNode();
    }

    // Inserts a word into the trie.
    void insert(string s) {
        TrieNode *cur = root;
        for (int i = 0; i < s.length(); i++) {
            char c = s[i] - 'a';
            if (cur->next[c] == NULL) {
                TrieNode *trie = new TrieNode();
                trie->value = c;
                cur->next[c] = trie;
            }
            if (i == s.length() - 1) {
             cur->next[c]->terminal = true;
            }
            cur = cur->next[c];
        }
    }

    // Returns if the word is in the trie.
    bool search(string key) {
        TrieNode *cur = root;
        for (int i = 0; i < key.length(); i++) {
            char c = key[i] - 'a';
            if (cur->next[c] == NULL) {
                return false;
            }
            if (i == key.length() - 1 && cur->next[c]->terminal) {
                return true;
            } 
            
            cur = cur->next[c];
        }
        
        return false;
    }

    // Returns if there is any word in the trie
    // that starts with the given prefix.
    bool startsWith(string prefix) {
        TrieNode *cur = root;
        for (int i = 0; i < prefix.length(); i++) {
            char c = prefix[i] - 'a';
            if (cur->next[c] == NULL) {
                return false;
            }
            
            cur = cur->next[c];
        }
        
        return true;
    }

private:
    TrieNode* root;
};

// Your Trie object will be instantiated and called as such:
// Trie trie;
// trie.insert("somestring");
// trie.search("key");

Java, updated on July-8th-2018
class Trie {
    class Node{
        public Map<Character, Node> next;
        public boolean isWord;
        public Node() {
            next = new HashMap<>();    
        }
    }
    
    private Node root;
    /** Initialize your data structure here. */
    public Trie() {
        root = new Node();
    }
    
    /** Inserts a word into the trie. */
    public void insert(String word) {
        Node node = root;
        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            if (!node.next.containsKey(c)) {
                node.next.put(c, new Node());
            }
            node = node.next.get(c);
        }
        node.isWord = true;
    }
    
    /** Returns if the word is in the trie. */
    public boolean search(String word) {
        Node node = getThatNode(word);
        return node != null && node.isWord;
    }
    
    /** Returns if there is any word in the trie that starts with the given prefix. */
    public boolean startsWith(String prefix) {
        return getThatNode(prefix) != null;
    }
    
    private Node getThatNode(String word) {
        Node node = root;
        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);
            if (!node.next.containsKey(c)) return null;
            node = node.next.get(c);
        }
        
        return node;
    }
}

/**
 * Your Trie object will be instantiated and called as such:
 * Trie obj = new Trie();
 * obj.insert(word);
 * boolean param_2 = obj.search(word);
 * boolean param_3 = obj.startsWith(prefix);
 */

Thursday, June 11, 2015

Day 105, ##, Binary Tree Right Side View, Number of Islands , Bitwise AND of Numbers Range, Happy Number, Remove Linked List Elements, Isomorphic Strings

Binary Tree Right Side View 
Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.
For example:
Given the following binary tree,
   1            <---
 /   \
2     3         <---
 \     \
  5     4       <---
You should return [1, 3, 4].
-------------------------------------------------------
Similar to level order traversal
can be done iteratively with a queue

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void side(vector<int> &rt, int level, TreeNode *root) {
        if (root == NULL) {
            return;
        }
        
        if (rt.size() < level) {
            rt.push_back(root->val);
        }else {
            rt[level - 1] = root->val;
        }
        
        side(rt,level + 1, root->left);
        side(rt,level + 1, root->right);
    }

    vector<int> rightSideView(TreeNode* root) {
        vector<int> rt;
        side(rt,1,root);
        return rt;
    }
};

Number of Islands
Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.
Example 1:
11110
11010
11000
00000
Answer: 1
Example 2:
11000
11000
00100
00011
Answer: 3
------------------------------------------------------
Solution #1 dfs
class Solution {
public:
    void dfs(vector<vector<char>>& grid, vector<vector<bool> > &visit, int row, int col) {
        if (row < 0 || row >= visit.size() || col < 0 || col >= visit[0].size() || visit[row][col] || grid[row][col] == '0') return;
        
        visit[row][col] = true;
        dfs(grid,visit,row + 1, col);
        dfs(grid,visit,row - 1, col);
        dfs(grid,visit,row, col + 1);
        dfs(grid,visit,row, col - 1);
    }

    int numIslands(vector<vector<char>>& grid) {
        int m = grid.size();
        if (m == 0) return 0;
        int n = grid[0].size();
        vector<vector<bool> > visit(m,vector<bool>(n,false));
        int count = 0;
        
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (!visit[i][j] && grid[i][j] == '1') {
                    count++;
                    dfs(grid,visit,i,j);
                }
                
            }
        }
        
        return count;
    }
};
Solution #2 bfs
class Solution {
public:
    void bfs(vector<vector<char>>& grid, vector<vector<bool> > &visit, int row, int col) {
        queue<pair<int,int> > que;
        que.push(make_pair(row,col));
        visit[row][col] = true;
        
        while (!que.empty()) {
            pair<int,int> point = que.front();
            que.pop();
            row = point.first;
            col = point.second;
            
            if (row + 1 < visit.size() && !visit[row + 1][col] && grid[row + 1][col] == '1') {
                que.push(make_pair(row + 1,col));
                visit[row + 1][col] = true;
            }
            
            if (row - 1 >= 0 && !visit[row - 1][col] && grid[row - 1][col] == '1') {
                que.push(make_pair(row - 1,col));
                visit[row - 1][col] = true;
            }
            
            if (col - 1 >= 0 && !visit[row][col - 1] && grid[row][col - 1] == '1') {
                que.push(make_pair(row,col - 1));
                visit[row][col - 1] = true;
            }
            
            if (col + 1 < visit[0].size() && !visit[row][col + 1] && grid[row][col + 1] == '1') {
                que.push(make_pair(row,col + 1));
                visit[row][col + 1] = true;
            }
        }
    }

    int numIslands(vector<vector<char>>& grid) {
        int m = grid.size();
        if (m == 0) return 0;
        int n = grid[0].size();
        vector<vector<bool> > visit(m,vector<bool>(n,false));
        int count = 0;
        
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (!visit[i][j] && grid[i][j] == '1') {
                    bfs(grid,visit,i,j);
                    count++;
                }
            }
        }
        
        return count;
    }
};

Bitwise AND of Numbers Range
Given a range [m, n] where 0 <= m <= n <= 2147483647, return the bitwise AND of all numbers in this range, inclusive.
For example, given the range [5, 7], you should return 4.
---------------------------------------
The idea is very simple:
  1. last bit of (odd number & even number) is 0.
  2. when m != n, There is at least an odd number and an even number, so the last bit position result is 0.
  3. Move m and n rigth a position.
Keep doing step 1,2,3 until m equal to n, use a factor to record the iteration time.
class Solution {
public:
    int rangeBitwiseAnd(int m, int n) {
        int count = 0;
        while (m != n) {
            m >>= 1;
            n >>= 1;
            count++;
        }
        
        return m << count;
    }
};
Happy Number
Write an algorithm to determine if a number is "happy".
A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers.
Example: 19 is a happy number
  • 12 + 92 = 82
  • 82 + 22 = 68
  • 62 + 82 = 100
  • 12 + 02 + 02 = 1
----------------------------------------------
class Solution {
public:
    bool isHappy(int n) {
        unordered_set<int> s;
        
        while (s.find(n) == s.end()) {
            if (n == 1) return true;
            s.insert(n);
            
            int sum = 0;
            while (n != 0) {
                sum += (n % 10) * (n % 10);
                n /= 10;
            }
            n = sum;
        }
        
        return false;
    }
};

Remove Linked List Elements
Remove all elements from a linked list of integers that have value val.
Example
Given: 1 --> 2 --> 6 --> 3 --> 4 --> 5 --> 6, val = 6
Return: 1 --> 2 --> 3 --> 4 --> 5
--------------------------------------------------------
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode *dummy = new ListNode(0);
        dummy->next = head;
        ListNode *itr = dummy;
        
        while (itr->next != NULL) {
            if (itr->next->val == val) {
                itr->next = itr->next->next;
            }else {a
                itr = itr->next;
            }
        }
        
        return dummy->next;
    }
};

Isomorphic Strings
Given two strings s and t, determine if they are isomorphic.
Two strings are isomorphic if the characters in s can be replaced to get t.
All occurrences of a character must be replaced with another character while preserving the order of characters. No two characters may map to the same character but a character may map to itself.
For example,
Given "egg", "add", return true.
Given "foo", "bar", return false.
Given "paper", "title", return true.
Note:
You may assume both s and t have the same length.
--------------------------------------------
class Solution {
public:
    bool isIsomorphic(string s, string t) {
        vector<char> dicS(256,'\0');
        vector<char> dicT(256,'\0');
        
        for (int i = 0; i < s.length(); i++) {
            if (dicS[s[i]] == '\0' && dicT[t[i]] == '\0') {
                dicS[s[i]] = t[i];
                dicT[t[i]] = s[i];
            }else if (dicS[s[i]] != t[i] || dicT[t[i]] != s[i]) {
                return false;
            }    
        }
        
        return true;
    }
};

Reverse Linked List
Reverse a singly linked list. 
----------------------------------------------------------------
Iterative
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode *newHead = NULL;
        while (head != NULL) {
            ListNode *temp = head->next;
            head->next = newHead;
            newHead = head;
            head = temp;
        }
        
        return newHead;
    }
};
Recursive
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *rev(ListNode* head, ListNode * newHead) {
        if (head == NULL) return newHead;
        ListNode *temp = head->next;
        head->next = newHead;
        return rev(temp,head);
    }

    ListNode* reverseList(ListNode* head) {
        return rev(head,NULL);
    }
};

Wednesday, January 28, 2015

Day 96, ##, Topological Sorting

Topological Sorting 

Given an directed graph, a topological order of the graph nodes is defined as follow:
  • For each directed edge A-->B in graph, A must before B in the order list.
  • The first node in the order can be any node in the graph with no nodes direct to it.
Find any topological order for the given graph.
Note
You can assume that there is at least one topological order in the graph.
Example
For graph as follow:

The topological order can be:
[0, 1, 2, 3, 4, 5]
or
[0, 2, 3, 1, 5, 4]
or
....

Challenge
Can you do it in both BFS and DFS?
----------------------------------------------------------------------------
 DFS
/**
 * Definition for Directed graph.
 * struct DirectedGraphNode {
 *     int label;
 *     vector<DirectedGraphNode *> neighbors;
 *     DirectedGraphNode(int x) : label(x) {};
 * };
 */
class Solution {
public:
    /**
     * @param graph: A list of Directed graph node
     * @return: Any topological order for the given graph.
     */
     
    void dfs(DirectedGraphNode * node, vector<DirectedGraphNode*> &rt,unordered_set<DirectedGraphNode*> &visit) {
        visit.insert(node);
        for (int i = 0; i < node->neighbors.size(); i++) {
            if (visit.find(node->neighbors[i]) == visit.end()) {
                dfs(node->neighbors[i], rt, visit);
            }
        }
        
        rt.push_back(node);
    }
     
    vector<DirectedGraphNode*> topSort(vector<DirectedGraphNode*> graph) {
        // write your code here
        vector<DirectedGraphNode*> rt;
        unordered_set<DirectedGraphNode*> visit;
        
        for (int i = 0; i < graph.size(); i++) {
            if (visit.find(graph[i]) == visit.end()) {
                dfs(graph[i],rt,visit);
            }
        }
        
        reverse(rt.begin(),rt.end());
        return rt;
    }
};