From 30e59e3410851e5f75fbcff2c857ac19b24220bc Mon Sep 17 00:00:00 2001 From: busker <165013324+hiroki-horiguchi-dev@users.noreply.github.com> Date: Tue, 7 Jul 2026 20:49:30 +0900 Subject: [PATCH] Update 105.md --- tree-bst/105.md | 102 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/tree-bst/105.md b/tree-bst/105.md index e69de29..0d76de9 100644 --- a/tree-bst/105.md +++ b/tree-bst/105.md @@ -0,0 +1,102 @@ +- [105. Construct Binary Tree from Preorder and Inorder Traversal](https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/description/) + - 方針 + - まず大前提、preorder, inorder の性質を忘れているのでリファレンスを見にいく + - [preorder](https://www.geeksforgeeks.org/dsa/preorder-traversal-of-binary-tree/), [inorder](https://www.geeksforgeeks.org/dsa/inorder-traversal-of-binary-tree/)、問題で与えられているサンプルで考えてみる + - `Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7], Output: [3,9,20,null,null,15,7]` + - preorder の先頭が必ずrootになることはわかる + - preorder の先頭要素で inorder ないを検索すると、inorder で 3 からみた時の index 0 ~ indexOf(3), indexOf(3) + 1 ~ inorder.length - 1 がそれぞれ左部分木、右部分木だとわかる + - と言うことは、なんか preorder の値を線形に走査していく中で、うまく範囲を考えれば済むんじゃね?と考える + - 以下のように考えてみるけど、left, right 要素を作る段階でこの方針だと無理だなと考える + ```java + for (int i = 0; i < preorder.length; i++) { + rootNode = new TreeNode(preorder(i)); + // array とする必要はなくて、index を与えるだけで良さそう + leftNodes = new Array(inorder(0) ~ inorder.indexOf(preorder(i))); + rightNodes = new Array(inorder.indexOf(preorder(i)) + 1 ~ inorder.length - 1); + + rootNode.left = // あれここからどうしよう。。再起で書かないとダメか。。 + + } + ``` + - 制約を見ると、Stack Over Flowはしなさそうなデータ量だな + ```java + preorder = [3,9,20,15,7]; + inorder = [9,3,15,20,7]; + + buildTree(int[] preorder, int[] inorder) { + // 以下の方針はダメそうだとわかる + // for (int rootVal : preOrder) { + // buildTree(rootVal, 0, inOrder - 1); + // } + this.preorder = preorder; + this.inorder = inorder; + return buildTree(0, 0, inorder.length - 1); + } + + TreeNode buildTree(int preIndex, int inStart, int inEnd) { + if (inStart > inEnd) { + return null; + } + int rootVal = preOrder(preIndex); + TreeNode root = new TreeNode(rootVal); + // あれ、ここのマジックナンバーってこれでいいんだっけ?? 動的にやらなきゃいけない気がする。。 + root.left = buildTree(preIndex + 1, inStart, inOrder.indexOf(rootVal)); + root.right = buildTree(preIndex + 2, inOrder.indexOf(rootVal), inEnd); + return root; + } + ``` + - ここで時間切れ、回答みる + - やはり、preorder 側のインデックスをどう進めっるんだっけ?(マジックナンバーの箇所) が問題 + - このマジックナンバーの箇所、右を構築する時は inorder でカウントできる左の要素数分を飛び越えないといけない。。これが思いつけなかった。。 + - (というか、テストケースを思いつけないのが悪いな。。そもそも inorder, preorder を覚えてない時点でこの問題出されたら詰んでる。。) +- 計算量 +- 実装時間 + +## 1st +- 方針で組み立てたものに加えていくつか工夫が必要 + - 工夫で頭のメモリを取られてしまうのがまだ馴染んでいない証拠か。。 + - 通るコードは書いたけど、どっちかというと inorder, preorder を正しく理解しているのか?それぞれから元の木を頭の中で組み上げられるか?の方が重要だと思う(ちなみに、inorder のみから元の構造を複合するのは無理、なぜならどこがルートかわからないから。preorder のみでも無理、[1,2] から 1 left to 2, 1 right to 2 の両方が作れてしまい、left or right が一意に定まらないから) + - 例えば、他のトラバーサルの組み合わせでは複合できるのか?とか?何と何があれば複合できるんだっけ?を理解しておけばそこまで怖くはないはず +```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 { + int[] preorder; + Map inorderWithIndex = new HashMap<>(); + + public TreeNode buildTree(int[] preorder, int[] inorder) { + this.preorder = preorder; + for (int i = 0; i < inorder.length; i++) { + inorderWithIndex.put(inorder[i], i); + } + return buildTreeHelper(0, 0, inorder.length - 1); + } + + private TreeNode buildTreeHelper(int preIndex, int inStart, int inEnd) { + if (inStart > inEnd) { + return null; + } + int rootVal = preorder[preIndex]; + TreeNode root = new TreeNode(rootVal); + int rootIndexInInorder = inorderWithIndex.get(rootVal); + + root.left = buildTreeHelper(preIndex + 1, inStart, rootIndexInInorder - 1); + root.right = buildTreeHelper(preIndex + (rootIndexInInorder - inStart) + 1, rootIndexInInorder + 1, inEnd); + + return root; + } +} +``` \ No newline at end of file