Wednesday, June 1, 2022

1120. Maximum Average Subtree

 一刷 05/2022

Version #1 DFS recursion

Time O(N)

Space O(N)

Runtime: 3 ms, faster than 10.29% of Java online submissions for Maximum Average Subtree.
Memory Usage: 45.1 MB, less than 46.99% of Java online submissions for Maximum Average Subtree.

/**

 * Definition for a binary tree node.

 * public class TreeNode {

 *     int val;

 *     TreeNode left;

 *     TreeNode right;

 *     TreeNode() {}

 *     TreeNode(int val) { this.val = val; }

 *     TreeNode(int val, TreeNode left, TreeNode right) {

 *         this.val = val;

 *         this.left = left;

 *         this.right = right;

 *     }

 * }

 */

class Solution {

    class NodeInfo {

        int count;

        double sum;

        public NodeInfo(int count, double sum) {

            this.count = count;

            this.sum = sum;

        }

    }

    public double maximumAverageSubtree(TreeNode root) {

        double[] maxAvg = new double[1];

        helper(root, maxAvg);

        return maxAvg[0];

    }

    

    private NodeInfo helper(TreeNode root, double[] maxAvg) {

        if (root == null) {

            return new NodeInfo(0, 0);

        }

        NodeInfo leftInfo = helper(root.left, maxAvg);

        NodeInfo rightInfo = helper(root.right, maxAvg);

        int count = leftInfo.count + rightInfo.count + 1;

        double sum = root.val + leftInfo.sum + rightInfo.sum;

        maxAvg[0] = Math.max(maxAvg[0], sum / count);

        return new NodeInfo(count, sum);

    }

}

Tuesday, May 31, 2022

598 · Zombie in Matrix [LintCode]

一刷 05/2022

 Version #1 BFS

Time O(MN)

Spance O(MN)

361 mstime cost

·

22.63 MBmemory cost

·

Your submission beats16.20 %Submissions

public class Solution {

/**
* @param grid: a 2D integer grid
* @return: an integer
*/
private static int WALL = 2;
private static int ZOMBIE = 1;
private static int HUMAN = 0;
private int[] dx = new int[]{1, 0, -1, 0};
private int[] dy = new int[]{0, -1, 0, 1};
public int zombie(int[][] grid) {
if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) {
return 0;
}
int rows = grid.length, cols = grid[0].length;
Queue<int[]> que = new ArrayDeque<>();
boolean[][] visited = new boolean[rows][cols];
int humanCnt = 0;
for (int y = 0; y < rows; y++) {
for (int x = 0; x < cols; x++) {
if (grid[y][x] == HUMAN) {
humanCnt++;
}
if (grid[y][x] == ZOMBIE) {
visited[y][x] = true;
que.offer(new int[]{x, y});
}
}
}
int days = 0;
while (!que.isEmpty()) {
int size = que.size();
days++;
while (size-- > 0) {
int[] curr = que.poll();
for (int i = 0; i < 4; i++) {
int nx = curr[0] + dx[i];
int ny = curr[1] + dy[i];
if (nx < 0 || nx >= cols || ny < 0 || ny >= rows) {
continue;
}
if (visited[ny][nx] || grid[ny][nx] == WALL) {
continue;
}
if (grid[ny][nx] == HUMAN) {
humanCnt--;
}
visited[ny][nx] = true;
que.offer(new int[]{nx, ny});
}
}
if (humanCnt == 0) {
return days;
}
}
return -1;
}

618 · Search Graph Nodes [LintCode]

2649 mstime cost

·

22.94 MBmemory cost

·

Your submission beats11.00 %Submissions


 /**

* Definition for graph node.
* class UndirectedGraphNode {
* int label;
* ArrayList<UndirectedGraphNode> neighbors;
* UndirectedGraphNode(int x) {
* label = x; neighbors = new ArrayList<UndirectedGraphNode>();
* }
* };
*/


public class Solution {
/*
* @param graph: a list of Undirected graph node
* @param values: a hash mapping, <UndirectedGraphNode, (int)value>
* @param node: an Undirected graph node
* @param target: An integer
* @return: a node
*/
public UndirectedGraphNode searchNode(ArrayList<UndirectedGraphNode> graph,
Map<UndirectedGraphNode, Integer> values,
UndirectedGraphNode node,
int target) {
// write your code here
Queue<UndirectedGraphNode> que = new ArrayDeque<>();
Set<UndirectedGraphNode> visited = new HashSet<>();
que.offer(node);
visited.add(node);
if (values.containsKey(node) && values.get(node) == target) {
return node;
}
while (!que.isEmpty()) {
UndirectedGraphNode curr = que.poll();
for (UndirectedGraphNode next : curr.neighbors) {
if (visited.contains(next)) {
continue;
}
if (values.containsKey(next) && values.get(next) == target) {
return next;
}
visited.add(next);
que.offer(next);
}
}
return null;
}
}

1462. Course Schedule IV

 一刷 05/2022

Version #1 Topological Sort


Time O(E + V)

Space O(E + V)

Runtime: 124 ms, faster than 26.97% of Java online submissions for Course Schedule IV.
Memory Usage: 70.2 MB, less than 58.24% of Java online submissions for Course Schedule IV.

class Solution {

    public List<Boolean> checkIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) {

        Set<Integer>[] graph = new HashSet[numCourses];

        int[] indegree = new int[numCourses];

        Set<Integer>[] preReq = new HashSet[numCourses];

        for (int i = 0; i < numCourses; i++) {

            graph[i] = new HashSet<>();

            preReq[i] = new HashSet<>();

        }

        for (int[] prerequisite : prerequisites) {

            int from = prerequisite[0];

            int to = prerequisite[1];

            graph[from].add(to);

            indegree[to]++;

        }

        Queue<Integer> que = new ArrayDeque<>();

        for (int i = 0; i < numCourses; i++) {

            if (indegree[i] == 0) {

                que.offer(i);

            }

        }

        

        while (!que.isEmpty()) {

            Integer curr = que.poll();

            for (int next : graph[curr]) {

                preReq[next].add(curr);

                preReq[next].addAll(preReq[curr]);

                indegree[next]--;

                if (indegree[next] == 0) {

                    que.offer(next);

                }

            }

        }

        List<Boolean> result = new ArrayList<>();

        for (int[] query : queries) {

            if (preReq[query[1]].contains(query[0])) {

                result.add(true);

            } else {

                result.add(false);

            }

        }

        return result;

    }

}

Monday, May 30, 2022

444. Sequence Reconstruction

 一刷 05/2022

Version #1 Topological Sort

Time O(#nums)

Space O(#nums^2)


class Solution {

    public boolean sequenceReconstruction(int[] nums, List<List<Integer>> sequences) {

        Map<Integer, Set<Integer>> graph = new HashMap<>();

        Map<Integer, Integer> indegree = new HashMap<>();

        for (int num : nums) {

            graph.put(num, new HashSet<>());

            indegree.put(num, 0);

        }

        for (List<Integer> sequence : sequences) {

            Integer from = null, to = null;

            for (Integer n : sequence) {

                if (from == null) {

                    from = n;

                    continue;

                }

                to = n;

                Set<Integer> neighbors = graph.get(from);

                if (!neighbors.contains(to)) {

                    neighbors.add(to);

                    indegree.put(to, indegree.get(to) + 1);

                }

                from = n;

            }

        }

        // for (Map.Entry<Integer, Set<Integer>> entry : graph.entrySet()) {

        //     System.out.printf("key-%d, set-%s\n", entry.getKey(), entry.getValue());

        // }

        Queue<Integer> que = new ArrayDeque<>();

        for (Map.Entry<Integer,Integer> entry : indegree.entrySet()) {

            if (entry.getValue() == 0) {

                que.offer(entry.getKey());

            }

        }

        int index = 0;

        while (!que.isEmpty()) {

            if (que.size() > 1) {

                return false;

            }

            Integer curr = que.poll();

            // System.out.println(curr);

            if (curr != nums[index++]) {

                return false;

            }

            for (Integer neighbor : graph.get(curr)) {

                int id = indegree.get(neighbor);

                id -= 1;

                if (id == 0) {

                    que.offer(neighbor);

                }

                indegree.put(neighbor, id);

            }

        }

        return true;

    }

}

Wednesday, May 25, 2022

1197. Minimum Knight Moves

 一刷

Version #1 BFS

TLE if we use HashMap to implement the visited grids

We should use a boolean array instead

Given the coordinate of the target as (x, y), the number of cells covered by the circle that is centered at point (0, 0) and reaches the target point is roughly \big(\max(|x|, |y|)\big) ^ 2

Time O(max(|x|, |y|)^2)

Space O(max(|x|, |y|)^2)

Runtime: 279 ms, faster than 60.99% of Java online submissions for Minimum Knight Moves.
Memory Usage: 91.8 MB, less than 54.57% of Java online submissions for Minimum Knight Moves.

class Solution {

    private int[] dx = new int[]{2, 1, -1, -2, -2, -1, 1, 2};

    private int[] dy = new int[]{1, 2, 2, 1, -1, -2, -2, -1};

    public int minKnightMoves(int x, int y) {

        if (x == 0 && y == 0) {

            return 0;

        }

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

        boolean[][] visited = new boolean[601][601];

        que.offer(new int[]{0, 0});

        visited[300][300] = true;

        int step = 0;

        while (!que.isEmpty()) {

            int size = que.size();

            step++;

            while (size-- > 0) {

                int[] curr = que.poll();

                // y = curr[0], x = curr[1]

                for (int i = 0; i < 8; i++) {

                    int ny = curr[0] + dy[i];

                    int nx = curr[1] + dx[i];

                    if (nx == x && ny == y) {

                        return step;

                    }

                    if (visited[ny + 300][nx + 300]) {

                        continue;

                    }

                    que.offer(new int[]{ny, nx});

                    visited[ny + 300][nx + 300] = true;

                }

            }

        }

        return -1;

    }

}


Version #2 Bidirectional BFS

这里只是记录这种bidirectional的思路

实际写的时候visited array的boundary和offsite都非常tricky, 写错了好几次

如果不用visited array而用hash成string的方法就会TLE

所以问题很多

Time 和 Space complexity都和上面是一样的

Runtime: 207 ms, faster than 68.90% of Java online submissions for Minimum Knight Moves.
Memory Usage: 74.4 MB, less than 56.56% of Java online submissions for Minimum Knight Moves.


class Solution {

    private int[] dx = new int[]{2, 1, -1, -2, -2, -1, 1, 2};

    private int[] dy = new int[]{1, 2, 2, 1, -1, -2, -2, -1};

    

    private String hash(int[] grid) {

        return grid[0] + "," + grid[1];

    }

    

    private int offsite = 600;

    public int minKnightMoves(int x, int y) {

        if (x == 0 && y == 0) {

            return 0;

        }

        // Bidirectional BFS

        // Search from both start point and the end point

        int bound = 1201;

        int[][] sourceVisited = new int[bound][bound];

        int[][] targetVisited = new int[bound][bound];

        for (int i = 0; i < bound; i++) {

            for (int j = 0; j < bound; j++) {

                sourceVisited[i][j] = -1;

                targetVisited[i][j] = -1;

            }

        }

        

        Queue<int[]> sourceQue = new ArrayDeque<>();

        sourceVisited[offsite][offsite] = 0;

        sourceQue.offer(new int[]{0, 0});

        

        Queue<int[]> targetQue = new ArrayDeque<>();

        targetVisited[x + offsite][y + offsite] = 0;

        targetQue.offer(new int[]{x, y});

        // while (!sourceQue.isEmpty() && !targetQue.isEmpty())

        // The queue will never be empty since the board is infinite, so we can just use while "true"

        while (true) {

            int dist = bfs(sourceQue, sourceVisited, targetVisited);

            if (dist > 0) {

                return dist;

            }      

            dist = bfs(targetQue, targetVisited, sourceVisited);

            if (dist > 0) {

                return dist;

            }

        }

    }


    private int bfs(Queue<int[]> que, int[][] selfVisited, int[][] otherVisited) {

        int[] curr = que.poll();

        

        // dist to the next point

        int dist = selfVisited[curr[0] + offsite][curr[1] + offsite] + 1;

        // System.out.printf("(%d,%d) -> %d", curr[0], curr[1], dist);

        for (int i = 0; i < 8; i++) {

            int nx = curr[0] + dx[i];

            int ny = curr[1] + dy[i];

            

            if (otherVisited[nx + offsite][ny + offsite] != -1) {

                return dist + otherVisited[nx + offsite][ny + offsite];

            }

            if (selfVisited[nx + offsite][ny + offsite] != -1) {

                continue;

            }

            selfVisited[nx + offsite][ny + offsite] = dist;

            que.offer(new int[]{nx, ny});

        }

        return -1;

    }

}

Tuesday, May 24, 2022

711. Number of Distinct Islands II

 一刷 05/2022

Version #1 BFS

参考LC649

重点是把一个island normalize

这里可以hash成一个string

StringBuilder append 加String.format很慢,要避免,最好一个一个append

Runtime: 281 ms, faster than 12.12% of Java online submissions for Number of Distinct Islands II.
Memory Usage: 73.3 MB, less than 16.67% of Java online submissions for Number of Distinct Islands II.

class Solution {

    public int numDistinctIslands2(int[][] grid) {

        // find all grids of an island

        // enumerate all transformations of that island

        // Normalize those transformations by calculating the relative position of the left & top point

        // Sort all the transformations and use the minimum representative to represent the island

        // Use a hash set to deduplicate

        if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) {

            return 0;

        }

        int rows = grid.length, cols = grid[0].length;

        boolean[][] visited = new boolean[rows][cols];

        Set<String> islands = new HashSet<>();

        for (int y = 0; y < rows; y++) {

            for (int x = 0; x < cols; x++) {

                if (!visited[y][x] && grid[y][x] == 1) {

                    String island = normalize(findIsland(grid, y, x, visited));

                    islands.add(island);

                }

            }

        }

        return islands.size();

    }

    

    private int[] dx = new int[]{1, 0, -1, 0};

    private int[] dy = new int[]{0, -1, 0, 1};

    private List<List<Integer>> findIsland(int[][] grid, int y, int x, boolean[][] visited) {

        List<List<Integer>> island = new ArrayList<>();

        Queue<List<Integer>> que = new ArrayDeque<>();

        que.offer(Arrays.asList(y, x));

        visited[y][x] = true;

        while (!que.isEmpty()) {

            List<Integer> curr = que.poll();

            island.add(curr);

            // go to 4 directions

            for (int i = 0; i < 4; i++) {

                int ny = curr.get(0) + dy[i];

                int nx = curr.get(1) + dx[i];

                // out of boundary

                if (ny < 0 || ny >= grid.length || nx < 0 || nx >= grid[0].length) {

                    continue;

                }

                if (!visited[ny][nx] && grid[ny][nx] == 1) {

                    visited[ny][nx] = true;

                    que.offer(Arrays.asList(ny, nx));

                }

            }

        }

        return island;

    }

    

    private String normalize(List<List<Integer>> island) {

        List<List<List<Integer>>> transformations = new ArrayList<>();

        List<String> strs = new ArrayList<>();

        for (int i = 0; i < 8; i++) {

            transformations.add(new ArrayList<>());

        }

        for (List<Integer> curr : island) {

            int y = curr.get(0);

            int x = curr.get(1);

            transformations.get(0).add(Arrays.asList(x, y));

            transformations.get(1).add(Arrays.asList(-x, y));

            transformations.get(2).add(Arrays.asList(x, -y));

            transformations.get(3).add(Arrays.asList(-x, -y));

            transformations.get(4).add(Arrays.asList(y, x));

            transformations.get(5).add(Arrays.asList(-y, x));

            transformations.get(6).add(Arrays.asList(y, -x));

            transformations.get(7).add(Arrays.asList(-y, -x));

        }

        StringBuilder sb = new StringBuilder();

        for (List<List<Integer>> transformation : transformations) {

            Collections.sort(transformation, new Comparator<List<Integer>>() {

                @Override

                public int compare(List<Integer> a, List<Integer> b) {

                    if (a.get(0) != b.get(0)) {

                        return a.get(0) - b.get(0);

                    }

                    return a.get(1) - b.get(1);

                }

            });

            Integer y0 = transformation.get(0).get(0);

            Integer x0 = transformation.get(0).get(1);

            for (int i = 0; i < transformation.size(); i++) {

                List<Integer> yx = transformation.get(i);

                // y = yx.get(0) - y0

                // x = yx.get(1) - x0

                sb.append("(" +  (yx.get(0) - y0) + "," +  (yx.get(1) - x0) + ")");

            }

            strs.add(sb.toString());

            sb.setLength(0);

        }

        Collections.sort(strs);

        return strs.get(0);

    }

}



Version #2 DFS

Runtime: 115 ms, faster than 45.45% of Java online submissions for Number of Distinct Islands II.
Memory Usage: 67.6 MB, less than 71.21% of Java online submissions for Number of Distinct Islands II.

class Solution {

    class Point implements Comparable<Point> {

        public int x, y;

        public Point(int x, int y) {

            this.x = x;

            this.y = y;

        }

        

        @Override

        public int compareTo(Point p) {

            if (this.y != p.y) {

                return this.y - p.y;

            }

            return this.x - p.x;

        }

        

        @Override

        public String toString() {

            return String.format("(%s,%s)", x, y);

        }

    } 

    public int numDistinctIslands2(int[][] grid) {

        // find all grids of an island

        // enumerate all transformations of that island

        // Normalize those transformations by calculating the relative position of the left & top point

        // Sort all the transformations and use the minimum representative to represent the island

        // Use a hash set to deduplicate

        if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) {

            return 0;

        }

        int rows = grid.length, cols = grid[0].length;

        boolean[][] visited = new boolean[rows][cols];

        Set<String> islands = new HashSet<>();

        for (int y = 0; y < rows; y++) {

            for (int x = 0; x < cols; x++) {

                if (!visited[y][x] && grid[y][x] == 1) {

                    List<Point> island = new ArrayList<>();

                    visited[y][x] = true;

                    findIsland(grid, y, x, visited, island);

                    String str = normalize(island);

                    islands.add(str);

                }

            }

        }

        return islands.size();

    }

    

    private int[] dx = new int[]{1, 0, -1, 0};

    private int[] dy = new int[]{0, -1, 0, 1};

    private void findIsland(int[][] grid, int y, int x, boolean[][] visited, List<Point> island) {

        island.add(new Point(x, y));

        for (int i = 0; i < 4; i++) {

            int ny = y + dy[i];

            int nx = x + dx[i];

            if (ny < 0 || ny >= grid.length || nx < 0 || nx >= grid[0].length) {

                continue;

            }

            if (!visited[ny][nx] && grid[ny][nx] == 1) {

                visited[ny][nx] = true;

                findIsland(grid, ny, nx, visited, island);

            }

        }

    }

    

    private String normalize(List<Point> island) {

        List<Point>[] transformations = new List[8];

        String[] strs = new String[8];

        for (int i = 0; i < 8; i++) {

            transformations[i] = new ArrayList<>();

        }

        for (Point p : island) {

            int y = p.y;

            int x = p.x;

            transformations[0].add(new Point(x, y));

            transformations[1].add(new Point(-x, y));

            transformations[2].add(new Point(x, -y));

            transformations[3].add(new Point(-x, -y));

            transformations[4].add(new Point(y, x));

            transformations[5].add(new Point(-y, x));

            transformations[6].add(new Point(y, -x));

            transformations[7].add(new Point(-y, -x));

        }

        

        for (int i = 0; i < 8; i++) {

            StringBuilder sb = new StringBuilder();

            Collections.sort(transformations[i]);

            int x0 = transformations[i].get(0).x;

            int y0 = transformations[i].get(0).y;

            for (Point p : transformations[i]) {

                sb.append(String.format("(%s,%s)", p.x - x0, p.y - y0));

            }

            strs[i] = sb.toString();

        }

        Arrays.sort(strs);

        return strs[0];

    }

}