diff --git a/779/solution1_1.java b/779/solution1_1.java new file mode 100644 index 0000000..fce9e08 --- /dev/null +++ b/779/solution1_1.java @@ -0,0 +1,50 @@ +/* +・概要 +自力解法。 +テストケースの洗い出しが足りず、そもそも求められているものと違うことに気づくが、解法がわからずACできず。 +15分くらい + +*/ + +import javax.swing.tree.TreeNode; + +public class solution1_1 { + public TreeNode[] splitBST(TreeNode root, int target) { + if (root.val == target) { + return new TreeNode[] {root, null}; + } + return new TreeNode[] {getTargetTreeAndChangeSubTree(root, target), root}; + } + + private TreeNode getTargetTreeAndChangeSubTree(TreeNode current, int target) { + if (current == null) { + return null; + } + if (target < current.val) { + if (current.left == null) { + return null; + } + if (current.left.val == target) { + TreeNode subTree = current.left; + current.left = current.left.right; + subTree.right = null; + return subTree; + } else { + return getTargetTreeAndChangeSubTree(current.left, target); + } + } else { + if (current.right == null) { + return null; + } + if (current.right.val == target) { + TreeNode subTree = current.right; + + current.right = current.right.left; + subTree.left = null; + return subTree; + } else { + return getTargetTreeAndChangeSubTree(current.right, target); + } + } + } +} diff --git a/779/solution2_1.java b/779/solution2_1.java new file mode 100644 index 0000000..82d00f7 --- /dev/null +++ b/779/solution2_1.java @@ -0,0 +1,45 @@ +/* +・概要 +LeetCodeの解説や他の人の解法をみた。 +https://github.com/Ryotaro25/leetcode_first60/pull/50/files + +・解法 +この問題では、元の木構造を保ちながら、target以下の値だけの木と、targetより大きい値の木に分けるという内容である。 +solution1_1で直感的にできそうだが、 + 8 + 3 9 + 4 + 5 +みたいな木でtargetが5のときに対応できない。 +ということで根から各々木を降りながらみていく。各再帰で返す値は、その時点でのtarget以下の木とtargetより大きいだけの木である。 +木の値がtarget以下であれば、左の部分木はBSTなのですべてその木の値以下なので構造を変える必要がない。逆に右の部分木はまだTarget以下の木がある可能性があるので、再帰で見る必要がある。 +再帰でかえされる二つの木の内、target以下の木については、現在の値よりは大きいはず(元々自身の右の部分木の一部なので)なので、右の部分木にする。 +木の値がtargetより大きい値であれば、先ほどと同様の動きで左の部分木をみていく。 + +・計算量 +O(h): 木の深さ + +・所感 +簡単なテストケースのみで問題の本質を誤認してしまった。またBSTの内容を理解していれば、単純に親との関係を見るだけではダメなことは気付けだはず。 +本質的な原因はテストケースの洗い出しが適当だったこと、LeetCodeのテストサンプルだけを鵜呑みにしたことが原因なので、 +https://github.com/goto-untrapped/Arai60/pull/54/files +にあるとおり、シンプルケース→もうすこし難しいケース→エッジケースの流れの洗い出しを必ずするようにする(まだ仕事での取り組み方とLeetCodeでの問題のやり方を分離していてよくない。) + +*/ + +public class solution2_1 { + public TreeNode[] splitBST(TreeNode root, int target) { + if (root == null) { + return new TreeNode[2]; + } + if (target < root.val) { + TreeNode[] small = splitBST(root.left, target); + root.left = leftSubTree[1]; + return new TreeNode[] {leftSubTree[0], root}; + } else { + TreeNode[] rightSubTree = splitBST(root.right, target); + root.right = rightSubTree[0]; + return new TreeNode[] {root, rightSubTree[1]}; + } + } +} diff --git a/779/solution2_2.java b/779/solution2_2.java new file mode 100644 index 0000000..68558d5 --- /dev/null +++ b/779/solution2_2.java @@ -0,0 +1,42 @@ +/* +・概要 +LeetCodeの解説や他の人の解法を見たもの +https://github.com/Ryotaro25/leetcode_first60/pull/50/files#diff-776c4af48e8dabf508f652032b95d33f3ef8308547e1fdd2dc55e447d6bc1af8R26 + +自分の言葉で頭を整理する。 + +・解法 +再帰を使わずに繰り返し処理で実装したもの +考え方は再帰と一緒だが、再帰のbottomupと違って、根から順々に処理していくので、上から順に木を繋げていく。 +繰り返し処理の部分は、再帰と一緒で現在の木の値がtarget以下かどうかで処理を分ける。 +現在見ている木の値がtarget以下の時は、target以下の木に繋げていく。現在のtarget以下の木の現在みているものをXとする。ここで気になるのはXの左右のどちらに繋ぐかということだが、 +Xの左の部分木は必ずtarget以下となっていて、そもそも探索する必要がないので探索してXに繋ぐ可能性があるのはXの右の部分木に含まれる木であり、つまりXより大きい値なのでXの右に繋ぐしかない。 +上記である通り、次に探索するのは現在の木の右の部分木となる。 +またこのときtarget以下の木についても現在の木に更新し、かつその木の右の部分木はtargetより大きい可能性もあるのでnullにする。 +現在見ている木の値がtarget以上の時も、上記と同様に行なっていく +*/ + +public class solution2_2 { + public TreeNode[] splitBST(TreeNode root, int target) { + TreeNode current = root; + TreeNode smallDummy = new TreeNode(0); + TreeNode largeDummy = new TreeNode(0); + TreeNode smallTail = smallDummy; + TreeNode largeTail = largeDummy; + + while (current != null) { + if (current.val <= target) { + smallTail.right = current; + smallTail = current; + current = current.right; + smallTail.right = null; + } else { + largeTail.left = current; + largeTail = current; + current = current.left; + largeTail.left = null; + } + } + return new TreeNode[] {smallDummy.right, largeDummy.left}; + } +}