742.ツリーの一番近いリーフノード


ID:742 TITLE:ツリーの一番近いリーフノードTAG:Java
方法一:図に変換する
ツリーを図に変換すると、最も近いリーフノードを幅優先検索で見つけることができます.
アルゴリズム:
  • 親ノードから深さ優先探索を行い、各ノードのエッジ
  • に記録する.
  • の後、kの値を持つノードを優先的に検索し、各ノードにノードkの距離順にアクセスします.リーフノードに遭遇すると、最も近いリーフノードになります.
  • class Solution(object):
        def findClosestLeaf(self, root, k):
            graph = collections.defaultdict(list)
            def dfs(node, par = None):
                if node:
                    graph[node].append(par)
                    graph[par].append(node)
                    dfs(node.left, node)
                    dfs(node.right, node)
    
            dfs(root)
            queue = collections.deque(node for node in graph
                                      if node and node.val == k)
            seen = set(queue)
    
            while queue:
                node = queue.popleft()
                if node:
                    if len(graph[node]) <= 1:
                        return node.val
                    for nei in graph[node]:
                        if nei not in seen:
                            seen.add(nei)
                            queue.append(nei)
    
    class Solution {
        public int findClosestLeaf(TreeNode root, int k) {
            Map> graph = new HashMap();
            dfs(graph, root, null);
    
            Queue queue = new LinkedList();
            Set seen = new HashSet();
    
            for (TreeNode node: graph.keySet()) {
                if (node != null && node.val == k) {
                    queue.add(node);
                    seen.add(node);
                }
            }
    
            while (!queue.isEmpty()) {
                TreeNode node = queue.poll();
                if (node != null) {
                    if (graph.get(node).size() <= 1)
                        return node.val;
                    for (TreeNode nei: graph.get(node)) {
                        if (!seen.contains(nei)) {
                            seen.add(nei);
                            queue.add(nei);
                        }
                    }
                }
            }
            throw null;
        }
    
        public void dfs(Map> graph, TreeNode node, TreeNode parent) {
            if (node != null) {
                if (!graph.containsKey(node)) graph.put(node, new LinkedList());
                if (!graph.containsKey(parent)) graph.put(parent, new LinkedList());
                graph.get(node).add(parent);
                graph.get(parent).add(node);
                dfs(graph, node.left, node);
                dfs(graph, node.right, node);
            }
        }
    }
    

    複雑度分析
  • 時間複雑度:O(N)O(N)O(N).N N Nは二叉木のノード数を指す.
  • 空間複雑度:O(N)O(N)O(N)、図の大きさ.

  • 方法2:
    アルゴリズム:
  • は、各ノードから、そのサブツリーの中で最も近いリーフノードがどこにあるかを知っていると仮定する.記憶化された遍歴を使って、これらの情報を記憶することができます.
  • そして、ターゲットに最も近いリーフノードは、targetと最も低い共通の祖先を有し、rootからtargetへの経路上にあるに違いない.rootからtargetへの経路を任意の有効な遍歴で見つけ、経路上の各ノードの注釈を見て、すべての候補リーフノードを決定し、最適な1つを選択することができます.
  • class Solution(object):
        def findClosestLeaf(self, root, k):
            annotation = {}
            def closest_leaf(root):
                if root not in annotation:
                    if not root:
                        ans = float('inf'), None
                    elif not root.left and not root.right:
                        ans = 0, root
                    else:
                        d1, leaf1 = closest_leaf(root.left)
                        d2, leaf2 = closest_leaf(root.right)
                        ans = min(d1, d2) + 1, leaf1 if d1 < d2 else leaf2
                    annotation[root] = ans
                return annotation[root]
    
            #Search for node.val == k
            path = []
            def dfs(node):
                if not node:
                    return
                if node.val == k:
                    path.append(node)
                    return True
                path.append(node)
                ans1 = dfs(node.left)
                if ans1: return True
                ans2 = dfs(node.right)
                if ans2: return True
                path.pop()
    
            dfs(root)
            dist, leaf = float('inf'), None
            for i, node in enumerate(path):
                d0, leaf0 = closest_leaf(node)
                d0 += len(path) - 1 - i
                if d0 < dist:
                    dist = d0
                    leaf = leaf0
    
            return leaf.val
    
    class Solution {
        List path;
        Map annotation;
    
        public int findClosestLeaf(TreeNode root, int k) {
            path = new ArrayList();
            annotation = new HashMap();
    
            dfs(root, k);
    
            int distanceFromTarget = path.size() - 1;
            int dist = Integer.MAX_VALUE;
            TreeNode leaf = null;
            for (TreeNode node: path) {
                LeafResult lr = closestLeaf(node);
                if (lr.dist + distanceFromTarget < dist) {
                    dist = lr.dist + distanceFromTarget;
                    leaf = lr.node;
                }
                distanceFromTarget--;
            }
            return leaf.val;
        }
    
        public boolean dfs(TreeNode node, int k) {
            if (node == null) {
                return false;
            } else if (node.val == k) {
                path.add(node);
                return true;
            } else {
                path.add(node);
                boolean ans = dfs(node.left, k);
                if (ans) return true;
                ans = dfs(node.right, k);
                if (ans) return true;
                path.remove(path.size() - 1);
                return false;
            }
        }
    
        public LeafResult closestLeaf(TreeNode root) {
            if (root == null) {
                return new LeafResult(null, Integer.MAX_VALUE);
            } else if (root.left == null && root.right == null) {
                return new LeafResult(root, 0);
            } else if (annotation.containsKey(root)) {
                return annotation.get(root);
            } else {
                LeafResult r1 = closestLeaf(root.left);
                LeafResult r2 = closestLeaf(root.right);
                LeafResult ans = new LeafResult(r1.dist < r2.dist ? r1.node : r2.node,
                                                Math.min(r1.dist, r2.dist) + 1);
                annotation.put(root, ans);
                return ans;
            }
        }
    }
    class LeafResult {
        TreeNode node;
        int dist;
        LeafResult(TreeNode n, int d) {
            node = n;
            dist = d;
        }
    }
    

    複雑度分析
  • 時空複雑度:O(N)O(N)O(N).解析は方法1と同じである.