From 48063f2890723185749f21d930576c9e7f095930 Mon Sep 17 00:00:00 2001 From: Dhanush Date: Tue, 16 Jul 2024 06:56:58 +0530 Subject: [PATCH 1/9] Optimized Solution --- .../Solution.java | 80 ++++++++----------- 1 file changed, 33 insertions(+), 47 deletions(-) diff --git a/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.java b/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.java index 79a6ea48a0a11..7e229f0491056 100644 --- a/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.java +++ b/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.java @@ -14,56 +14,42 @@ * } */ class Solution { - private Map>> edges; - private Set visited; - private String ans; - + static byte[] path = new byte[200_001]; + int strtLevel = -1; + int destLevel = -1; + int comnLevel = -1; + public String getDirections(TreeNode root, int startValue, int destValue) { - edges = new HashMap<>(); - visited = new HashSet<>(); - ans = null; - traverse(root); - dfs(startValue, destValue, new ArrayList<>()); - return ans; + findPaths(root, startValue, destValue, 100_000); + int answerIdx = comnLevel; + for (int i = strtLevel; i > comnLevel; i--) + path[--answerIdx] = 'U'; + return new String(path, answerIdx, destLevel - answerIdx); } - - private void traverse(TreeNode root) { - if (root == null) { - return; + + private int findPaths(TreeNode node, int strtVal, int destVal, int level) { + if (node == null) return 0; + int result = 0; + if (node.val == strtVal) { + strtLevel = level; + result = 1; + } else if (node.val == destVal) { + destLevel = level; + result = 1; } - if (root.left != null) { - edges.computeIfAbsent(root.val, k -> new ArrayList<>()) - .add(Arrays.asList(String.valueOf(root.left.val), "L")); - edges.computeIfAbsent(root.left.val, k -> new ArrayList<>()) - .add(Arrays.asList(String.valueOf(root.val), "U")); - } - if (root.right != null) { - edges.computeIfAbsent(root.val, k -> new ArrayList<>()) - .add(Arrays.asList(String.valueOf(root.right.val), "R")); - edges.computeIfAbsent(root.right.val, k -> new ArrayList<>()) - .add(Arrays.asList(String.valueOf(root.val), "U")); - } - traverse(root.left); - traverse(root.right); - } - - private void dfs(int start, int dest, List t) { - if (visited.contains(start)) { - return; - } - if (start == dest) { - if (ans == null || ans.length() > t.size()) { - ans = String.join("", t); - } - return; - } - visited.add(start); - if (edges.containsKey(start)) { - for (List item : edges.get(start)) { - t.add(item.get(1)); - dfs(Integer.parseInt(item.get(0)), dest, t); - t.remove(t.size() - 1); + int leftFound = 0; + int rightFound = 0; + if (comnLevel < 0) { + if (destLevel < 0) path[level] = 'L'; + leftFound = findPaths(node.left, strtVal, destVal, level + 1); + rightFound = 0; + if (comnLevel < 0) { + if (destLevel < 0) path[level] = 'R'; + rightFound = findPaths(node.right, strtVal, destVal, level + 1); } } + if (comnLevel < 0 && leftFound + rightFound + result == 2) + comnLevel = level; + return result | leftFound | rightFound; } -} \ No newline at end of file +} From ef89d2ae70d65a818d5e03c0632aec09bb907ac4 Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Tue, 16 Jul 2024 16:19:14 +0800 Subject: [PATCH 2/9] Update README.md --- .../README.md | 409 ++++++++++++------ 1 file changed, 288 insertions(+), 121 deletions(-) diff --git a/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/README.md b/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/README.md index c7e958f93e469..c351918569317 100644 --- a/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/README.md +++ b/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/README.md @@ -72,7 +72,11 @@ tags: -### 方法一 +### 方法一:最近公共祖先 + DFS + +我们可以先找到节点 $\textit{startValue}$ 和 $\textit{destValue}$ 的最近公共祖先,记为 $\textit{node}$,然后分别从 $\textit{node}$ 出发,找到 $\textit{startValue}$ 和 $\textit{destValue}$ 的路径。那么从 $\textit{startValue}$ 到 $\textit{node}$ 的路径就是 $\textit{U}$ 的个数,从 $\textit{node}$ 到 $\textit{destValue}$ 的路径就是 $\textit{path}$ 的路径,最后将这两个路径拼接起来即可。 + +时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为二叉树的节点数。 @@ -85,115 +89,88 @@ tags: # self.val = val # self.left = left # self.right = right + + class Solution: def getDirections( self, root: Optional[TreeNode], startValue: int, destValue: int ) -> str: - edges = defaultdict(list) - ans = None - visited = set() - - def traverse(root): - if not root: - return - if root.left: - edges[root.val].append([root.left.val, 'L']) - edges[root.left.val].append([root.val, 'U']) - if root.right: - edges[root.val].append([root.right.val, 'R']) - edges[root.right.val].append([root.val, 'U']) - traverse(root.left) - traverse(root.right) - - def dfs(start, dest, t): - nonlocal ans - if start in visited: - return - if start == dest: - if ans is None or len(ans) > len(t): - ans = ''.join(t) - return - visited.add(start) - for d, k in edges[start]: - t.append(k) - dfs(d, dest, t) - t.pop() - - traverse(root) - dfs(startValue, destValue, []) - return ans + def lca(node: Optional[TreeNode], p: int, q: int): + if node is None or node.val in (p, q): + return node + left = lca(node.left, p, q) + right = lca(node.right, p, q) + if left and right: + return node + return left or right + + def dfs(node: Optional[TreeNode], x: int, path: List[str]): + if node is None: + return False + if node.val == x: + return True + path.append("L") + if dfs(node.left, x, path): + return True + path[-1] = "R" + if dfs(node.right, x, path): + return True + path.pop() + return False + + node = lca(root, startValue, destValue) + + path_to_start = [] + path_to_dest = [] + + dfs(node, startValue, path_to_start) + dfs(node, destValue, path_to_dest) + + return "U" * len(path_to_start) + "".join(path_to_dest) ``` #### Java ```java -/** - * 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 { - private Map>> edges; - private Set visited; - private String ans; - public String getDirections(TreeNode root, int startValue, int destValue) { - edges = new HashMap<>(); - visited = new HashSet<>(); - ans = null; - traverse(root); - dfs(startValue, destValue, new ArrayList<>()); - return ans; + TreeNode node = lca(root, startValue, destValue); + StringBuilder pathToStart = new StringBuilder(); + StringBuilder pathToDest = new StringBuilder(); + dfs(node, startValue, pathToStart); + dfs(node, destValue, pathToDest); + return "U".repeat(pathToStart.length()) + pathToDest.toString(); } - private void traverse(TreeNode root) { - if (root == null) { - return; - } - if (root.left != null) { - edges.computeIfAbsent(root.val, k -> new ArrayList<>()) - .add(Arrays.asList(String.valueOf(root.left.val), "L")); - edges.computeIfAbsent(root.left.val, k -> new ArrayList<>()) - .add(Arrays.asList(String.valueOf(root.val), "U")); + private TreeNode lca(TreeNode node, int p, int q) { + if (node == null || node.val == p || node.val == q) { + return node; } - if (root.right != null) { - edges.computeIfAbsent(root.val, k -> new ArrayList<>()) - .add(Arrays.asList(String.valueOf(root.right.val), "R")); - edges.computeIfAbsent(root.right.val, k -> new ArrayList<>()) - .add(Arrays.asList(String.valueOf(root.val), "U")); + TreeNode left = lca(node.left, p, q); + TreeNode right = lca(node.right, p, q); + if (left != null && right != null) { + return node; } - traverse(root.left); - traverse(root.right); + return left != null ? left : right; } - private void dfs(int start, int dest, List t) { - if (visited.contains(start)) { - return; + private boolean dfs(TreeNode node, int x, StringBuilder path) { + if (node == null) { + return false; } - if (start == dest) { - if (ans == null || ans.length() > t.size()) { - ans = String.join("", t); - } - return; + if (node.val == x) { + return true; } - visited.add(start); - if (edges.containsKey(start)) { - for (List item : edges.get(start)) { - t.add(item.get(1)); - dfs(Integer.parseInt(item.get(0)), dest, t); - t.remove(t.size() - 1); - } + path.append('L'); + if (dfs(node.left, x, path)) { + return true; + } + path.setCharAt(path.length() - 1, 'R'); + if (dfs(node.right, x, path)) { + return true; } + path.deleteCharAt(path.length() - 1); + return false; } } ``` @@ -214,50 +191,240 @@ class Solution { */ class Solution { public: - unordered_map>> edges; - unordered_set visited; - string ans; - string getDirections(TreeNode* root, int startValue, int destValue) { - ans = ""; - traverse(root); - string t = ""; - dfs(startValue, destValue, t); - return ans; + TreeNode* node = lca(root, startValue, destValue); + string pathToStart, pathToDest; + dfs(node, startValue, pathToStart); + dfs(node, destValue, pathToDest); + return string(pathToStart.size(), 'U') + pathToDest; } - void traverse(TreeNode* root) { - if (!root) return; - if (root->left) { - edges[root->val].push_back({root->left->val, 'L'}); - edges[root->left->val].push_back({root->val, 'U'}); +private: + TreeNode* lca(TreeNode* node, int p, int q) { + if (node == nullptr || node->val == p || node->val == q) { + return node; } - if (root->right) { - edges[root->val].push_back({root->right->val, 'R'}); - edges[root->right->val].push_back({root->val, 'U'}); + TreeNode* left = lca(node->left, p, q); + TreeNode* right = lca(node->right, p, q); + if (left != nullptr && right != nullptr) { + return node; } - traverse(root->left); - traverse(root->right); + return left != nullptr ? left : right; } - void dfs(int start, int dest, string& t) { - if (visited.count(start)) return; - if (start == dest) { - if (ans == "" || ans.size() > t.size()) ans = t; - return; + bool dfs(TreeNode* node, int x, string& path) { + if (node == nullptr) { + return false; } - visited.insert(start); - if (edges.count(start)) { - for (auto& item : edges[start]) { - t += item.second; - dfs(item.first, dest, t); - t.pop_back(); - } + if (node->val == x) { + return true; + } + path.push_back('L'); + if (dfs(node->left, x, path)) { + return true; } + path.back() = 'R'; + if (dfs(node->right, x, path)) { + return true; + } + path.pop_back(); + return false; } }; ``` +#### Go + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func getDirections(root *TreeNode, startValue int, destValue int) string { + var lca func(node *TreeNode, p, q int) *TreeNode + lca = func(node *TreeNode, p, q int) *TreeNode { + if node == nil || node.Val == p || node.Val == q { + return node + } + left := lca(node.Left, p, q) + right := lca(node.Right, p, q) + if left != nil && right != nil { + return node + } + if left != nil { + return left + } + return right + } + var dfs func(node *TreeNode, x int, path *[]byte) bool + dfs = func(node *TreeNode, x int, path *[]byte) bool { + if node == nil { + return false + } + if node.Val == x { + return true + } + *path = append(*path, 'L') + if dfs(node.Left, x, path) { + return true + } + (*path)[len(*path)-1] = 'R' + if dfs(node.Right, x, path) { + return true + } + *path = (*path)[:len(*path)-1] + return false + } + + node := lca(root, startValue, destValue) + pathToStart := []byte{} + pathToDest := []byte{} + dfs(node, startValue, &pathToStart) + dfs(node, destValue, &pathToDest) + return string(bytes.Repeat([]byte{'U'}, len(pathToStart))) + string(pathToDest) +} +``` + +#### TypeScript + +```ts +/** + * Definition for a binary tree node. + * class TreeNode { + * val: number + * left: TreeNode | null + * right: TreeNode | null + * constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + * } + */ + +function getDirections(root: TreeNode | null, startValue: number, destValue: number): string { + const lca = (node: TreeNode | null, p: number, q: number): TreeNode | null => { + if (node === null || node.val === p || node.val === q) { + return node; + } + const left = lca(node.left, p, q); + const right = lca(node.right, p, q); + if (left !== null && right !== null) { + return node; + } + return left !== null ? left : right; + }; + + const dfs = (node: TreeNode | null, x: number, path: string[]): boolean => { + if (node === null) { + return false; + } + if (node.val === x) { + return true; + } + path.push('L'); + if (dfs(node.left, x, path)) { + return true; + } + path[path.length - 1] = 'R'; + if (dfs(node.right, x, path)) { + return true; + } + path.pop(); + return false; + }; + + const node = lca(root, startValue, destValue); + const pathToStart: string[] = []; + const pathToDest: string[] = []; + dfs(node, startValue, pathToStart); + dfs(node, destValue, pathToDest); + return 'U'.repeat(pathToStart.length) + pathToDest.join(''); +} +``` + + + + + + + +#### 方法二:DFS + + + +#### Java + +```java +/** + * 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 { + static byte[] path = new byte[200_001]; + int strtLevel = -1; + int destLevel = -1; + int comnLevel = -1; + + public String getDirections(TreeNode root, int startValue, int destValue) { + findPaths(root, startValue, destValue, 100_000); + int answerIdx = comnLevel; + for (int i = strtLevel; i > comnLevel; i--) { + path[--answerIdx] = 'U'; + } + return new String(path, answerIdx, destLevel - answerIdx); + } + + private int findPaths(TreeNode node, int strtVal, int destVal, int level) { + if (node == null) { + return 0; + } + int result = 0; + if (node.val == strtVal) { + strtLevel = level; + result = 1; + } else if (node.val == destVal) { + destLevel = level; + result = 1; + } + int leftFound = 0; + int rightFound = 0; + if (comnLevel < 0) { + if (destLevel < 0) { + path[level] = 'L'; + } + leftFound = findPaths(node.left, strtVal, destVal, level + 1); + rightFound = 0; + if (comnLevel < 0) { + if (destLevel < 0) { + path[level] = 'R'; + } + rightFound = findPaths(node.right, strtVal, destVal, level + 1); + } + } + if (comnLevel < 0 && leftFound + rightFound + result == 2) { + comnLevel = level; + } + return result | leftFound | rightFound; + } +} +``` + From 7b1304c96b70122476b1f4a4714f33445f9cfee4 Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Tue, 16 Jul 2024 16:19:38 +0800 Subject: [PATCH 3/9] Update README_EN.md --- .../README_EN.md | 409 ++++++++++++------ 1 file changed, 288 insertions(+), 121 deletions(-) diff --git a/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/README_EN.md b/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/README_EN.md index f83a49ec6545c..013717c1cd162 100644 --- a/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/README_EN.md +++ b/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/README_EN.md @@ -68,7 +68,11 @@ tags: -### Solution 1 +### Solution 1: Lowest Common Ancestor + DFS + +We can first find the lowest common ancestor of nodes $\textit{startValue}$ and $\textit{destValue}$, denoted as $\textit{node}$. Then, starting from $\textit{node}$, we find the paths to $\textit{startValue}$ and $\textit{destValue}$ respectively. The path from $\textit{startValue}$ to $\textit{node}$ will consist of a number of $\textit{U}$s, and the path from $\textit{node}$ to $\textit{destValue}$ will be the $\textit{path}$. Finally, we concatenate these two paths. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the binary tree. @@ -81,115 +85,88 @@ tags: # self.val = val # self.left = left # self.right = right + + class Solution: def getDirections( self, root: Optional[TreeNode], startValue: int, destValue: int ) -> str: - edges = defaultdict(list) - ans = None - visited = set() - - def traverse(root): - if not root: - return - if root.left: - edges[root.val].append([root.left.val, 'L']) - edges[root.left.val].append([root.val, 'U']) - if root.right: - edges[root.val].append([root.right.val, 'R']) - edges[root.right.val].append([root.val, 'U']) - traverse(root.left) - traverse(root.right) - - def dfs(start, dest, t): - nonlocal ans - if start in visited: - return - if start == dest: - if ans is None or len(ans) > len(t): - ans = ''.join(t) - return - visited.add(start) - for d, k in edges[start]: - t.append(k) - dfs(d, dest, t) - t.pop() - - traverse(root) - dfs(startValue, destValue, []) - return ans + def lca(node: Optional[TreeNode], p: int, q: int): + if node is None or node.val in (p, q): + return node + left = lca(node.left, p, q) + right = lca(node.right, p, q) + if left and right: + return node + return left or right + + def dfs(node: Optional[TreeNode], x: int, path: List[str]): + if node is None: + return False + if node.val == x: + return True + path.append("L") + if dfs(node.left, x, path): + return True + path[-1] = "R" + if dfs(node.right, x, path): + return True + path.pop() + return False + + node = lca(root, startValue, destValue) + + path_to_start = [] + path_to_dest = [] + + dfs(node, startValue, path_to_start) + dfs(node, destValue, path_to_dest) + + return "U" * len(path_to_start) + "".join(path_to_dest) ``` #### Java ```java -/** - * 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 { - private Map>> edges; - private Set visited; - private String ans; - public String getDirections(TreeNode root, int startValue, int destValue) { - edges = new HashMap<>(); - visited = new HashSet<>(); - ans = null; - traverse(root); - dfs(startValue, destValue, new ArrayList<>()); - return ans; + TreeNode node = lca(root, startValue, destValue); + StringBuilder pathToStart = new StringBuilder(); + StringBuilder pathToDest = new StringBuilder(); + dfs(node, startValue, pathToStart); + dfs(node, destValue, pathToDest); + return "U".repeat(pathToStart.length()) + pathToDest.toString(); } - private void traverse(TreeNode root) { - if (root == null) { - return; - } - if (root.left != null) { - edges.computeIfAbsent(root.val, k -> new ArrayList<>()) - .add(Arrays.asList(String.valueOf(root.left.val), "L")); - edges.computeIfAbsent(root.left.val, k -> new ArrayList<>()) - .add(Arrays.asList(String.valueOf(root.val), "U")); + private TreeNode lca(TreeNode node, int p, int q) { + if (node == null || node.val == p || node.val == q) { + return node; } - if (root.right != null) { - edges.computeIfAbsent(root.val, k -> new ArrayList<>()) - .add(Arrays.asList(String.valueOf(root.right.val), "R")); - edges.computeIfAbsent(root.right.val, k -> new ArrayList<>()) - .add(Arrays.asList(String.valueOf(root.val), "U")); + TreeNode left = lca(node.left, p, q); + TreeNode right = lca(node.right, p, q); + if (left != null && right != null) { + return node; } - traverse(root.left); - traverse(root.right); + return left != null ? left : right; } - private void dfs(int start, int dest, List t) { - if (visited.contains(start)) { - return; + private boolean dfs(TreeNode node, int x, StringBuilder path) { + if (node == null) { + return false; } - if (start == dest) { - if (ans == null || ans.length() > t.size()) { - ans = String.join("", t); - } - return; + if (node.val == x) { + return true; } - visited.add(start); - if (edges.containsKey(start)) { - for (List item : edges.get(start)) { - t.add(item.get(1)); - dfs(Integer.parseInt(item.get(0)), dest, t); - t.remove(t.size() - 1); - } + path.append('L'); + if (dfs(node.left, x, path)) { + return true; + } + path.setCharAt(path.length() - 1, 'R'); + if (dfs(node.right, x, path)) { + return true; } + path.deleteCharAt(path.length() - 1); + return false; } } ``` @@ -210,50 +187,240 @@ class Solution { */ class Solution { public: - unordered_map>> edges; - unordered_set visited; - string ans; - string getDirections(TreeNode* root, int startValue, int destValue) { - ans = ""; - traverse(root); - string t = ""; - dfs(startValue, destValue, t); - return ans; + TreeNode* node = lca(root, startValue, destValue); + string pathToStart, pathToDest; + dfs(node, startValue, pathToStart); + dfs(node, destValue, pathToDest); + return string(pathToStart.size(), 'U') + pathToDest; } - void traverse(TreeNode* root) { - if (!root) return; - if (root->left) { - edges[root->val].push_back({root->left->val, 'L'}); - edges[root->left->val].push_back({root->val, 'U'}); +private: + TreeNode* lca(TreeNode* node, int p, int q) { + if (node == nullptr || node->val == p || node->val == q) { + return node; } - if (root->right) { - edges[root->val].push_back({root->right->val, 'R'}); - edges[root->right->val].push_back({root->val, 'U'}); + TreeNode* left = lca(node->left, p, q); + TreeNode* right = lca(node->right, p, q); + if (left != nullptr && right != nullptr) { + return node; } - traverse(root->left); - traverse(root->right); + return left != nullptr ? left : right; } - void dfs(int start, int dest, string& t) { - if (visited.count(start)) return; - if (start == dest) { - if (ans == "" || ans.size() > t.size()) ans = t; - return; + bool dfs(TreeNode* node, int x, string& path) { + if (node == nullptr) { + return false; } - visited.insert(start); - if (edges.count(start)) { - for (auto& item : edges[start]) { - t += item.second; - dfs(item.first, dest, t); - t.pop_back(); - } + if (node->val == x) { + return true; + } + path.push_back('L'); + if (dfs(node->left, x, path)) { + return true; } + path.back() = 'R'; + if (dfs(node->right, x, path)) { + return true; + } + path.pop_back(); + return false; } }; ``` +#### Go + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func getDirections(root *TreeNode, startValue int, destValue int) string { + var lca func(node *TreeNode, p, q int) *TreeNode + lca = func(node *TreeNode, p, q int) *TreeNode { + if node == nil || node.Val == p || node.Val == q { + return node + } + left := lca(node.Left, p, q) + right := lca(node.Right, p, q) + if left != nil && right != nil { + return node + } + if left != nil { + return left + } + return right + } + var dfs func(node *TreeNode, x int, path *[]byte) bool + dfs = func(node *TreeNode, x int, path *[]byte) bool { + if node == nil { + return false + } + if node.Val == x { + return true + } + *path = append(*path, 'L') + if dfs(node.Left, x, path) { + return true + } + (*path)[len(*path)-1] = 'R' + if dfs(node.Right, x, path) { + return true + } + *path = (*path)[:len(*path)-1] + return false + } + + node := lca(root, startValue, destValue) + pathToStart := []byte{} + pathToDest := []byte{} + dfs(node, startValue, &pathToStart) + dfs(node, destValue, &pathToDest) + return string(bytes.Repeat([]byte{'U'}, len(pathToStart))) + string(pathToDest) +} +``` + +#### TypeScript + +```ts +/** + * Definition for a binary tree node. + * class TreeNode { + * val: number + * left: TreeNode | null + * right: TreeNode | null + * constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + * } + */ + +function getDirections(root: TreeNode | null, startValue: number, destValue: number): string { + const lca = (node: TreeNode | null, p: number, q: number): TreeNode | null => { + if (node === null || node.val === p || node.val === q) { + return node; + } + const left = lca(node.left, p, q); + const right = lca(node.right, p, q); + if (left !== null && right !== null) { + return node; + } + return left !== null ? left : right; + }; + + const dfs = (node: TreeNode | null, x: number, path: string[]): boolean => { + if (node === null) { + return false; + } + if (node.val === x) { + return true; + } + path.push('L'); + if (dfs(node.left, x, path)) { + return true; + } + path[path.length - 1] = 'R'; + if (dfs(node.right, x, path)) { + return true; + } + path.pop(); + return false; + }; + + const node = lca(root, startValue, destValue); + const pathToStart: string[] = []; + const pathToDest: string[] = []; + dfs(node, startValue, pathToStart); + dfs(node, destValue, pathToDest); + return 'U'.repeat(pathToStart.length) + pathToDest.join(''); +} +``` + + + + + + + +#### Solution 2: DFS + + + +#### Java + +```java +/** + * 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 { + static byte[] path = new byte[200_001]; + int strtLevel = -1; + int destLevel = -1; + int comnLevel = -1; + + public String getDirections(TreeNode root, int startValue, int destValue) { + findPaths(root, startValue, destValue, 100_000); + int answerIdx = comnLevel; + for (int i = strtLevel; i > comnLevel; i--) { + path[--answerIdx] = 'U'; + } + return new String(path, answerIdx, destLevel - answerIdx); + } + + private int findPaths(TreeNode node, int strtVal, int destVal, int level) { + if (node == null) { + return 0; + } + int result = 0; + if (node.val == strtVal) { + strtLevel = level; + result = 1; + } else if (node.val == destVal) { + destLevel = level; + result = 1; + } + int leftFound = 0; + int rightFound = 0; + if (comnLevel < 0) { + if (destLevel < 0) { + path[level] = 'L'; + } + leftFound = findPaths(node.left, strtVal, destVal, level + 1); + rightFound = 0; + if (comnLevel < 0) { + if (destLevel < 0) { + path[level] = 'R'; + } + rightFound = findPaths(node.right, strtVal, destVal, level + 1); + } + } + if (comnLevel < 0 && leftFound + rightFound + result == 2) { + comnLevel = level; + } + return result | leftFound | rightFound; + } +} +``` + From ecc2caa3edc18c6a53ac8364633c1eae6789f9f2 Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Tue, 16 Jul 2024 16:19:52 +0800 Subject: [PATCH 4/9] Update Solution.py --- .../Solution.py | 61 ++++++++++--------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.py b/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.py index 063713ad935bc..2963576fc9e60 100644 --- a/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.py +++ b/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.py @@ -4,40 +4,41 @@ # self.val = val # self.left = left # self.right = right + + class Solution: def getDirections( self, root: Optional[TreeNode], startValue: int, destValue: int ) -> str: - edges = defaultdict(list) - ans = None - visited = set() + def lca(node: Optional[TreeNode], p: int, q: int): + if node is None or node.val in (p, q): + return node + left = lca(node.left, p, q) + right = lca(node.right, p, q) + if left and right: + return node + return left or right + + def dfs(node: Optional[TreeNode], x: int, path: List[str]): + if node is None: + return False + if node.val == x: + return True + path.append("L") + if dfs(node.left, x, path): + return True + path[-1] = "R" + if dfs(node.right, x, path): + return True + path.pop() + return False + + node = lca(root, startValue, destValue) - def traverse(root): - if not root: - return - if root.left: - edges[root.val].append([root.left.val, 'L']) - edges[root.left.val].append([root.val, 'U']) - if root.right: - edges[root.val].append([root.right.val, 'R']) - edges[root.right.val].append([root.val, 'U']) - traverse(root.left) - traverse(root.right) + path_to_start = [] + path_to_dest = [] - def dfs(start, dest, t): - nonlocal ans - if start in visited: - return - if start == dest: - if ans is None or len(ans) > len(t): - ans = ''.join(t) - return - visited.add(start) - for d, k in edges[start]: - t.append(k) - dfs(d, dest, t) - t.pop() + dfs(node, startValue, path_to_start) + dfs(node, destValue, path_to_dest) - traverse(root) - dfs(startValue, destValue, []) - return ans + return "U" * len(path_to_start) + "".join(path_to_dest) From f6c43c02fb57085f369fd0f8c60947c792c8f132 Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Tue, 16 Jul 2024 16:20:13 +0800 Subject: [PATCH 5/9] Update Solution.java --- .../Solution.java | 82 ++++++++----------- 1 file changed, 34 insertions(+), 48 deletions(-) diff --git a/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.java b/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.java index 7e229f0491056..7d20d1033ed99 100644 --- a/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.java +++ b/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.java @@ -1,55 +1,41 @@ -/** - * 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 { - static byte[] path = new byte[200_001]; - int strtLevel = -1; - int destLevel = -1; - int comnLevel = -1; - public String getDirections(TreeNode root, int startValue, int destValue) { - findPaths(root, startValue, destValue, 100_000); - int answerIdx = comnLevel; - for (int i = strtLevel; i > comnLevel; i--) - path[--answerIdx] = 'U'; - return new String(path, answerIdx, destLevel - answerIdx); + TreeNode node = lca(root, startValue, destValue); + StringBuilder pathToStart = new StringBuilder(); + StringBuilder pathToDest = new StringBuilder(); + dfs(node, startValue, pathToStart); + dfs(node, destValue, pathToDest); + return "U".repeat(pathToStart.length()) + pathToDest.toString(); } - - private int findPaths(TreeNode node, int strtVal, int destVal, int level) { - if (node == null) return 0; - int result = 0; - if (node.val == strtVal) { - strtLevel = level; - result = 1; - } else if (node.val == destVal) { - destLevel = level; - result = 1; + + private TreeNode lca(TreeNode node, int p, int q) { + if (node == null || node.val == p || node.val == q) { + return node; } - int leftFound = 0; - int rightFound = 0; - if (comnLevel < 0) { - if (destLevel < 0) path[level] = 'L'; - leftFound = findPaths(node.left, strtVal, destVal, level + 1); - rightFound = 0; - if (comnLevel < 0) { - if (destLevel < 0) path[level] = 'R'; - rightFound = findPaths(node.right, strtVal, destVal, level + 1); - } + TreeNode left = lca(node.left, p, q); + TreeNode right = lca(node.right, p, q); + if (left != null && right != null) { + return node; } - if (comnLevel < 0 && leftFound + rightFound + result == 2) - comnLevel = level; - return result | leftFound | rightFound; + return left != null ? left : right; + } + + private boolean dfs(TreeNode node, int x, StringBuilder path) { + if (node == null) { + return false; + } + if (node.val == x) { + return true; + } + path.append('L'); + if (dfs(node.left, x, path)) { + return true; + } + path.setCharAt(path.length() - 1, 'R'); + if (dfs(node.right, x, path)) { + return true; + } + path.deleteCharAt(path.length() - 1); + return false; } } From ae28373790c1a3c401ad2844cd4cc6677a15e3c4 Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Tue, 16 Jul 2024 16:20:25 +0800 Subject: [PATCH 6/9] Update Solution.cpp --- .../Solution.cpp | 62 +++++++++---------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.cpp b/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.cpp index 8b85567ffb3c9..f847e2980ae12 100644 --- a/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.cpp +++ b/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.cpp @@ -11,45 +11,43 @@ */ class Solution { public: - unordered_map>> edges; - unordered_set visited; - string ans; - string getDirections(TreeNode* root, int startValue, int destValue) { - ans = ""; - traverse(root); - string t = ""; - dfs(startValue, destValue, t); - return ans; + TreeNode* node = lca(root, startValue, destValue); + string pathToStart, pathToDest; + dfs(node, startValue, pathToStart); + dfs(node, destValue, pathToDest); + return string(pathToStart.size(), 'U') + pathToDest; } - void traverse(TreeNode* root) { - if (!root) return; - if (root->left) { - edges[root->val].push_back({root->left->val, 'L'}); - edges[root->left->val].push_back({root->val, 'U'}); +private: + TreeNode* lca(TreeNode* node, int p, int q) { + if (node == nullptr || node->val == p || node->val == q) { + return node; } - if (root->right) { - edges[root->val].push_back({root->right->val, 'R'}); - edges[root->right->val].push_back({root->val, 'U'}); + TreeNode* left = lca(node->left, p, q); + TreeNode* right = lca(node->right, p, q); + if (left != nullptr && right != nullptr) { + return node; } - traverse(root->left); - traverse(root->right); + return left != nullptr ? left : right; } - void dfs(int start, int dest, string& t) { - if (visited.count(start)) return; - if (start == dest) { - if (ans == "" || ans.size() > t.size()) ans = t; - return; + bool dfs(TreeNode* node, int x, string& path) { + if (node == nullptr) { + return false; + } + if (node->val == x) { + return true; + } + path.push_back('L'); + if (dfs(node->left, x, path)) { + return true; } - visited.insert(start); - if (edges.count(start)) { - for (auto& item : edges[start]) { - t += item.second; - dfs(item.first, dest, t); - t.pop_back(); - } + path.back() = 'R'; + if (dfs(node->right, x, path)) { + return true; } + path.pop_back(); + return false; } -}; \ No newline at end of file +}; From 4fca4928569811e8e3e6de34a0e1793441f0b517 Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Tue, 16 Jul 2024 16:20:44 +0800 Subject: [PATCH 7/9] Create Solution.go --- .../Solution.go | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.go diff --git a/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.go b/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.go new file mode 100644 index 0000000000000..6e01984cb6c69 --- /dev/null +++ b/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.go @@ -0,0 +1,51 @@ +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func getDirections(root *TreeNode, startValue int, destValue int) string { + var lca func(node *TreeNode, p, q int) *TreeNode + lca = func(node *TreeNode, p, q int) *TreeNode { + if node == nil || node.Val == p || node.Val == q { + return node + } + left := lca(node.Left, p, q) + right := lca(node.Right, p, q) + if left != nil && right != nil { + return node + } + if left != nil { + return left + } + return right + } + var dfs func(node *TreeNode, x int, path *[]byte) bool + dfs = func(node *TreeNode, x int, path *[]byte) bool { + if node == nil { + return false + } + if node.Val == x { + return true + } + *path = append(*path, 'L') + if dfs(node.Left, x, path) { + return true + } + (*path)[len(*path)-1] = 'R' + if dfs(node.Right, x, path) { + return true + } + *path = (*path)[:len(*path)-1] + return false + } + + node := lca(root, startValue, destValue) + pathToStart := []byte{} + pathToDest := []byte{} + dfs(node, startValue, &pathToStart) + dfs(node, destValue, &pathToDest) + return string(bytes.Repeat([]byte{'U'}, len(pathToStart))) + string(pathToDest) +} From 5378a7d99bfc14b9520a9849689b0142aeb6043f Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Tue, 16 Jul 2024 16:20:58 +0800 Subject: [PATCH 8/9] Create Solution.ts --- .../Solution.ts | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.ts diff --git a/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.ts b/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.ts new file mode 100644 index 0000000000000..4ff0e716117f2 --- /dev/null +++ b/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution.ts @@ -0,0 +1,53 @@ +/** + * Definition for a binary tree node. + * class TreeNode { + * val: number + * left: TreeNode | null + * right: TreeNode | null + * constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + * } + */ + +function getDirections(root: TreeNode | null, startValue: number, destValue: number): string { + const lca = (node: TreeNode | null, p: number, q: number): TreeNode | null => { + if (node === null || node.val === p || node.val === q) { + return node; + } + const left = lca(node.left, p, q); + const right = lca(node.right, p, q); + if (left !== null && right !== null) { + return node; + } + return left !== null ? left : right; + }; + + const dfs = (node: TreeNode | null, x: number, path: string[]): boolean => { + if (node === null) { + return false; + } + if (node.val === x) { + return true; + } + path.push('L'); + if (dfs(node.left, x, path)) { + return true; + } + path[path.length - 1] = 'R'; + if (dfs(node.right, x, path)) { + return true; + } + path.pop(); + return false; + }; + + const node = lca(root, startValue, destValue); + const pathToStart: string[] = []; + const pathToDest: string[] = []; + dfs(node, startValue, pathToStart); + dfs(node, destValue, pathToDest); + return 'U'.repeat(pathToStart.length) + pathToDest.join(''); +} From 3f107b28dad6227cb6839f6adf2af47197a09683 Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Tue, 16 Jul 2024 16:21:11 +0800 Subject: [PATCH 9/9] Create Solution2.java --- .../Solution2.java | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution2.java diff --git a/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution2.java b/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution2.java new file mode 100644 index 0000000000000..4c16d80a5f41a --- /dev/null +++ b/solution/2000-2099/2096.Step-By-Step Directions From a Binary Tree Node to Another/Solution2.java @@ -0,0 +1,63 @@ +/** + * 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 { + static byte[] path = new byte[200_001]; + int strtLevel = -1; + int destLevel = -1; + int comnLevel = -1; + + public String getDirections(TreeNode root, int startValue, int destValue) { + findPaths(root, startValue, destValue, 100_000); + int answerIdx = comnLevel; + for (int i = strtLevel; i > comnLevel; i--) { + path[--answerIdx] = 'U'; + } + return new String(path, answerIdx, destLevel - answerIdx); + } + + private int findPaths(TreeNode node, int strtVal, int destVal, int level) { + if (node == null) { + return 0; + } + int result = 0; + if (node.val == strtVal) { + strtLevel = level; + result = 1; + } else if (node.val == destVal) { + destLevel = level; + result = 1; + } + int leftFound = 0; + int rightFound = 0; + if (comnLevel < 0) { + if (destLevel < 0) { + path[level] = 'L'; + } + leftFound = findPaths(node.left, strtVal, destVal, level + 1); + rightFound = 0; + if (comnLevel < 0) { + if (destLevel < 0) { + path[level] = 'R'; + } + rightFound = findPaths(node.right, strtVal, destVal, level + 1); + } + } + if (comnLevel < 0 && leftFound + rightFound + result == 2) { + comnLevel = level; + } + return result | leftFound | rightFound; + } +}