Thursday, November 15, 2018

863. All Nodes Distance K in Binary Tree

二刷 07/2022
Version #2 Recursive DFS
完全自己bug free写出来了感觉思路还是挺清晰的
关键是helper function返回的是target到当前node的距离
Time O(N)
Space O(N)
Runtime: 17 ms, faster than 53.43% of Java online submissions for All Nodes Distance K in Binary Tree.
Memory Usage: 42.8 MB, less than 72.00% of Java online submissions for All Nodes Distance K in Binary Tree.

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<Integer> distanceK(TreeNode root, TreeNode target, int k) {
        // given a root, if target is on its left, get the depth of the target from root, and find the depth of k - d - 1 nodes on the right subtree
        // repeat the same process if the target is on its right
        // if the node itself is the target, return all nodes that have depth k
        List<Integer> result = new ArrayList<>();
        findTarget(root, target, k, result);
        return result;
    }
    
    // Returns the target depth from the current node
    private Integer findTarget(TreeNode node, TreeNode target, int k, List<Integer> result) {
        if (node == null) {
            return null;
        }
        if (node == target) {
            addNodeOfDepth(node, k, result);
            return 0;
        }
        Integer left = findTarget(node.left, target, k, result);
        if (left != null) {
            // target is in the left subtree
            if (left + 1 == k) {
                result.add(node.val);
            } else if (left + 1 < k) {
                addNodeOfDepth(node.right, k - left - 2, result);
            }
            return left + 1;
        }
        Integer right = findTarget(node.right, target, k, result);
        if (right != null) {
            // target is in the right subtree
            if (right + 1 == k) {
                result.add(node.val);
            } else if (right + 1 < k) {
                addNodeOfDepth(node.left, k - right - 2, result);
            }
            return right + 1;
        }
        return null;
    }
    
    private void addNodeOfDepth(TreeNode node, int d, List<Integer> result) {
        if (node == null) {
            return;
        }
        if (d == 0) {
            result.add(node.val);
            return;
        }
        addNodeOfDepth(node.left, d - 1, result);
        addNodeOfDepth(node.right, d - 1, result);
    }

}

Version #1 Build Parent Mapping + BFS
非常straight forward的做法
复杂度没问题,performance有点慢
Time O(N)
Space O(N)
Runtime: 23 ms, faster than 16.07% of Java online submissions for All Nodes Distance K in Binary Tree.
Memory Usage: 43.1 MB, less than 56.39% of Java online submissions for All Nodes Distance K in Binary Tree.
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<Integer> distanceK(TreeNode root, TreeNode target, int k) {
        Map<TreeNode, TreeNode> parent = new HashMap<>();
        buildGraph(root, parent, null);
        Queue<TreeNode> que = new ArrayDeque<>();
        Set<TreeNode> visited = new HashSet<>();
        que.offer(target);
        visited.add(target);
        
        while (!que.isEmpty() && k != 0) {
            int size = que.size();
            k--;
            while (size-- > 0) {
                TreeNode curr = que.poll();
                if (parent.containsKey(curr) && visited.add(parent.get(curr))) {
                    que.offer(parent.get(curr));
                }
                if (curr.left != null && visited.add(curr.left)) {
                    que.offer(curr.left);
                }
                if (curr.right != null && visited.add(curr.right)) {
                    que.offer(curr.right);
                }
            }
        }
        
        List<Integer> result = new ArrayList<>();
        while (k == 0 && !que.isEmpty()) {
            result.add(que.poll().val);
        }
        return result;
    }
    
    private void buildGraph(TreeNode node, Map<TreeNode, TreeNode> parent, TreeNode parentNode) {
        if (node == null) {
            return;
        }
        if (parentNode != null) {
            parent.put(node, parentNode);
        }
        buildGraph(node.left, parent, node);
        buildGraph(node.right, parent, node);
    }
}



Version #2 DFS

[1] 1 3
[0,1,null,3,2] 2 1
[3,5,1,6,2,0,8,null,null,7,4] 5 2
[0,1,null,null,2,null,3,null,4] 3 0
Tooooooo many edge cases that need to be taken care of carefully
80.11 %
class Solution {
    public List<Integer> distanceK(TreeNode root, TreeNode target, int K) {
List<Integer> result = new ArrayList<>();
// either in its subtree, or in the subtree of its lowest common ancestors
dfs(root, target, K, result);
return result;
}

// returns how many steps is current node away from target, -1 if target is not in the subtree of current node
private int dfs(TreeNode node, TreeNode target, int K, List<Integer> result) {
if (node == null) return -1;
if (node == target) {
find(node, K, result);
return 0;
}
int l = dfs(node.left, target, K, result);
int r = dfs(node.right, target, K, result);
if (l < 0 && r < 0) {
return -1;
} else if (l >= 0 && l + 1 == K || r >= 0 && r + 1 == K) {
result.add(node.val);
return -1;
} else if (l >= 0) {
find(node.right, K - l - 2, result);
return l + 1;
} else if (r >= 0) {
find(node.left, K - r - 2, result);
return r + 1;
}
return -1;
}

private void find(TreeNode node, int m, List<Integer> result) {
if (node == null || m < 0) return;
// find nodes that are m node from current node
if (m == 0) {
result.add(node.val);
return;
}
find(node.left, m - 1, result);
find(node.right, m - 1, result);
}
}


Version #1 Naive Build Graph + BFS
Stream 无解的慢。。。这个60%是去掉stream以后的performance

60.03 %
class Solution {
    public List<Integer> distanceK(TreeNode root, TreeNode target, int K) {
        Map<TreeNode, List<TreeNode>> graph = new HashMap<>();
        if (root != null) {
            graph.put(root, new ArrayList<>());
        }
        build(root, graph);
        Queue<TreeNode> que = new LinkedList<>();
        Set<TreeNode> visited = new HashSet<>();
        que.offer(target);
        visited.add(target);
     
        while (!que.isEmpty() && K > 0) {
            int size = que.size();
            while (size-- > 0) {
                List<TreeNode> nexts = graph.get(que.poll());
                for (TreeNode next : nexts) {
                    if (!visited.contains(next)) {
                        que.offer(next);
                        visited.add(next);
                    }
                }
            }
            K--;
        }
        if (K == 0) {
            return que.stream().map(node -> node.val).collect(Collectors.toList());
        } else {
            return new ArrayList<>();
        }
     
    }
 
    private void build(TreeNode node, Map<TreeNode, List<TreeNode>> graph) {
        if (node == null) {
            return;
        }
        if (node.left != null) {
            graph.put(node.left, new ArrayList<>());
            graph.get(node).add(node.left);
            graph.get(node.left).add(node);
            build(node.left, graph);
        }
     
        if (node.right != null) {
            graph.put(node.right, new ArrayList<>());
            graph.get(node).add(node.right);
            graph.get(node.right).add(node);
            build(node.right, graph);
        }
    }
}

No comments:

Post a Comment