diff --git a/617/solution1_1.java b/617/solution1_1.java new file mode 100644 index 0000000..24ebeda --- /dev/null +++ b/617/solution1_1.java @@ -0,0 +1,29 @@ +// 自力解法。10分くらいでAC +// 時間計算量: O(n) n:2つの木の要素数、空間計算量: O(n) +// 左の木と右の木について処理はほぼ一緒なので関数化したかったが、left, rightが微妙に厄介で思いつかなかった。 +public class solution1_1 { + public TreeNode mergeTrees(TreeNode root1, TreeNode root2) { + if (root1 == null && root2 == null) { + return null; + } + int r1Value = root1 != null ? root1.val : 0; + int l1Value = root2 != null ? root2.val : 0; + TreeNode mergedNode = new TreeNode(r1Value + l1Value); + + if (root1 == null) { + mergedNode.left = root2.left; + } else if (root2 == null) { + mergedNode.left = root1.left; + } else { + mergedNode.left = mergeTrees(root1.left, root2.left); + } + if (root1 == null) { + mergedNode.right = root2.right; + } else if (root2 == null) { + mergedNode.right = root1.right; + } else { + mergedNode.right = mergeTrees(root1.right, root2.right); + } + return mergedNode; + } +} diff --git a/617/solution2_1.java b/617/solution2_1.java new file mode 100644 index 0000000..03d3f5f --- /dev/null +++ b/617/solution2_1.java @@ -0,0 +1,18 @@ +/** + * LeetCodeの解法を参考にしたもの。 計算量はsolution1_1と変わりなし。 + * 対象がnullだったら別の方を返すだけでよく、両方ある時は値を合算して、再帰するだけでいいというものだった。自力解法のときに再帰した時にどうなるかをイメージが甘かったなと気付かされた。 + */ +public class solution2_1 { + public TreeNode mergeTrees(TreeNode root1, TreeNode root2) { + if (root1 == null) { + return root2; + } + if (root2 == null) { + return root1; + } + TreeNode mergedTree = new TreeNode(root1.val + root2.val); + mergedTree.left = mergeTrees(root1.left, root2.left); + mergedTree.right = mergeTrees(root1.right, root2.right); + return mergedTree; + } +} diff --git a/617/solution2_2.java b/617/solution2_2.java new file mode 100644 index 0000000..0742dd4 --- /dev/null +++ b/617/solution2_2.java @@ -0,0 +1,26 @@ +/** + * solution2_1についてhttps://github.com/colorbox/leetcode/pull/37/filesのコメントにあった、入力の木と出力の木で共有されている場合があることに備えて、すべて新しい木を生成しなおしたもの + * * + */ +public class solution2_2 { + public TreeNode mergeTrees(TreeNode root1, TreeNode root2) { + if (root1 == null && root2 == null) { + return null; + } else if (root1 == null) { + return makeOneChildTree(root2); + } else if (root2 == null) { + return makeOneChildTree(root1); + } + TreeNode mergedTree = new TreeNode(root1.val + root2.val); + mergedTree.left = mergeTrees(root1.left, root2.left); + mergedTree.right = mergeTrees(root1.right, root2.right); + return mergedTree; + } + + private TreeNode makeOneChildTree(TreeNode child) { + TreeNode tree = new TreeNode(child.val); + tree.left = mergeTrees(null, child.left); + tree.right = mergeTrees(null, child.right); + return tree; + } +} diff --git a/617/solution2_3.java b/617/solution2_3.java new file mode 100644 index 0000000..78c3918 --- /dev/null +++ b/617/solution2_3.java @@ -0,0 +1,75 @@ +/** + * https://github.com/seal-azarashi/leetcode/pull/22/filesなどを参考にStackを用いたDFS + * 左と右でほぼ同様の処理をしているが、うまく関数として切り出せなかった。。 + * 実装中に恥ずかしながら左右木が両方nullのときは、mergeをnullにするだけでいいと誤認していたが、mergeをnullにしても、その親の木からの参照はnullにならずに悩んだ。 + * 変数mergeをnullにしてもmergeの参照先がnullになるだけで、親の木がみている元々の参照は残り続けるから→特にNode系を扱う時は参照がどうなっているのかをしっかり意識したい。 + */ +public class solution2_3 { + public TreeNode mergeTrees(TreeNode root1, TreeNode root2) { + + if (root1 == null && root2 == null) { + return null; + } + // 配列でやってるが、構造体を用意してもいい。 + Stack nodesForMerge = new Stack<>(); + TreeNode mergedTree = new TreeNode(); + if (root1 == null) { + mergedTree.val = root2.val; + } else if (root2 == null) { + mergedTree.val = root1.val; + } else { + mergedTree.val = root1.val + root2.val; + } + nodesForMerge.push(new TreeNode[] {mergedTree, root1, root2}); + + while (!nodesForMerge.isEmpty()) { + TreeNode[] nodes = nodesForMerge.pop(); + TreeNode merge = nodes[0]; + TreeNode left = nodes[1]; + TreeNode right = nodes[2]; + + TreeNode nextMergedLeftNode = new TreeNode(); + if (left == null) { + merge.val = right.val; + if (right.left != null) { + merge.left = nextMergedLeftNode; + nodesForMerge.push(new TreeNode[] {nextMergedLeftNode, null, right.left}); + } + } else if (right == null) { + merge.val = left.val; + if (left.left != null) { + merge.left = nextMergedLeftNode; + nodesForMerge.push(new TreeNode[] {nextMergedLeftNode, left.left, null}); + } + } else { + merge.val = left.val + right.val; + if (left.left != null || right.left != null) { + merge.left = nextMergedLeftNode; + nodesForMerge.push(new TreeNode[] {nextMergedLeftNode, left.left, right.left}); + } + } + + TreeNode nextMergedRightNode = new TreeNode(); + if (left == null) { + merge.val = right.val; + if (right.right != null) { + nodesForMerge.push(new TreeNode[] {nextMergedRightNode, null, right.right}); + merge.right = nextMergedRightNode; + } + } else if (right == null) { + merge.val = left.val; + if (left.right != null) { + nodesForMerge.push(new TreeNode[] {nextMergedRightNode, left.right, null}); + merge.right = nextMergedRightNode; + } + } else { + merge.val = left.val + right.val; + if (left.right != null || right.right != null) { + nodesForMerge.push(new TreeNode[] {nextMergedRightNode, left.right, right.right}); + merge.right = nextMergedRightNode; + } + } + } + return mergedTree; + } +} diff --git a/617/solution3_1.java b/617/solution3_1.java new file mode 100644 index 0000000..6b11256 --- /dev/null +++ b/617/solution3_1.java @@ -0,0 +1,39 @@ +/** + * いただいたコメントを元に修正したもの。 具体的には番兵を使った分岐処理の削除、変数名の変更、Stackに追加する構造体の定義を行なった。 + * 番兵については、連結リストでつかったり、ループでも使える場面もあるので条件分岐が大きくなったら番兵で減らせないかを考える癖をつける + */ +public class solution3_1 { + public TreeNode mergeTrees(TreeNode root1, TreeNode root2) { + if (root1 == null && root2 == null) { + return null; + } + Stack nodesForMerge = new Stack<>(); + TreeNode mergedTree = new TreeNode(); + nodesForMerge.push(new TreeForMerge(mergedTree, root1, root2)); + while (!nodesForMerge.isEmpty()) { + TreeForMerge nodes = nodesForMerge.pop(); + TreeNode merge = nodes.merge; + if (nodes.node1 == null && nodes.node2 == null) { + continue; + } + TreeNode node1 = nodes.node1 != null ? nodes.node1 : new TreeNode(0); + TreeNode node2 = nodes.node2 != null ? nodes.node2 : new TreeNode(0); + merge.val = node1.val + node2.val; + + if (node1.left != null || node2.left != null) { + TreeNode leftNode = new TreeNode(); + merge.left = leftNode; + nodesForMerge.push(new TreeForMerge(leftNode, node1.left, node2.left)); + } + if (node1.right != null || node2.right != null) { + TreeNode rightNode = new TreeNode(); + merge.right = rightNode; + nodesForMerge.push(new TreeForMerge(rightNode, node1.right, node2.right)); + } + } + return mergedTree; + } + + record TreeForMerge(TreeNode merge, TreeNode node1, TreeNode node2) {} + ; +}