From cc2a58ec746ffa5313af5a21151ec35a90446635 Mon Sep 17 00:00:00 2001 From: Terence Ponce Date: Sat, 9 Dec 2023 10:14:57 +0000 Subject: [PATCH] Solve 572 - Subtree of Another Tree (#22) --- .../00572_subtree_of_another_tree/README.md | 63 +++++++++++++ .../subtree_of_another_tree.ex | 42 +++++++++ .../subtree_of_another_tree_test.exs | 94 +++++++++++++++++++ 3 files changed, 199 insertions(+) create mode 100644 lib/solutions/00572_subtree_of_another_tree/README.md create mode 100644 lib/solutions/00572_subtree_of_another_tree/subtree_of_another_tree.ex create mode 100644 test/solutions/00572_subtree_of_another_tree/subtree_of_another_tree_test.exs diff --git a/lib/solutions/00572_subtree_of_another_tree/README.md b/lib/solutions/00572_subtree_of_another_tree/README.md new file mode 100644 index 0000000..a675a5c --- /dev/null +++ b/lib/solutions/00572_subtree_of_another_tree/README.md @@ -0,0 +1,63 @@ +# Subtree of Another Tree + +**Link to Problem**: https://leetcode.com/problems/subtree-of-another-tree + +## Description + +Given the roots of two binary trees `root` and `subRoot`, return `true` if there is a subtree of +root with the same structure and node values of `subRoot` and `false` otherwise. + +A subtree of a binary tree `tree` is a tree that consists of a node in `tree` and all of this +node's descendants. The tree `tree` could also be considered as a subtree of itself. + +## Examples + +### Example 1 + +```mermaid +graph + A(root) --> B((3)) + B --> C((4)) + B --> D((5)) + C --> E((1)) + C --> F((2)) + + G(subRoot) --> H((4)) + H --> I((1)) + H --> J((2)) +``` + +``` +Input: root = [3,4,5,1,2], subRoot = [4,1,2] +Output: true +``` + +### Example 2 + +```mermaid +graph + A((root)) --> B((3)) + B --> C((4)) + B --> D((5)) + C --> E((1)) + C --> F((2)) + F --> G((0)) + F --> H((nil)) + + I(subRoot) --> J((4)) + J --> K((1)) + J --> L((2)) +``` + +``` +Input: root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2] +Output: false +``` + +## Thoughts + +Part of the solution for this comes from [100 - Same Tree](../00100_same_tree), so I just reused that. + +The thing that I struggled with in this problem was figuring out how to end the recursion and keep it going. + +It's actually just really simple, but getting to that solution was not something that just came to me naturally. diff --git a/lib/solutions/00572_subtree_of_another_tree/subtree_of_another_tree.ex b/lib/solutions/00572_subtree_of_another_tree/subtree_of_another_tree.ex new file mode 100644 index 0000000..a597503 --- /dev/null +++ b/lib/solutions/00572_subtree_of_another_tree/subtree_of_another_tree.ex @@ -0,0 +1,42 @@ +defmodule LeetCodePractice.Solutions.SubtreeOfAnotherTree do + @moduledoc """ + Given the roots of two binary trees root and subRoot, return true if there is a subtree of root + with the same structure and node values of subRoot and false otherwise. + + A subtree of a binary tree tree is a tree that consists of a node in tree and all of this node's + descendants. The tree tree could also be considered as a subtree of itself. + """ + + alias LeetCodePractice.Provisions.TreeNode + + @spec call(root :: TreeNode.t() | nil, sub_root :: TreeNode.t() | nil) :: boolean + def call(root, sub_root) do + subtree?(root, sub_root) + end + + defp subtree?(nil, nil), do: true + defp subtree?(nil, _), do: false + + defp subtree?(root, sub_root) do + if same_tree?(root, sub_root) do + true + else + subtree?(root.left, sub_root) || subtree?(root.right, sub_root) + end + end + + defp same_tree?(%TreeNode{val: p_val, left: p_left, right: p_right}, %TreeNode{ + val: q_val, + left: q_left, + right: q_right + }) do + if p_val == q_val do + same_tree?(p_left, q_left) && same_tree?(p_right, q_right) + else + false + end + end + + defp same_tree?(nil, nil), do: true + defp same_tree?(_, _), do: false +end diff --git a/test/solutions/00572_subtree_of_another_tree/subtree_of_another_tree_test.exs b/test/solutions/00572_subtree_of_another_tree/subtree_of_another_tree_test.exs new file mode 100644 index 0000000..a838be4 --- /dev/null +++ b/test/solutions/00572_subtree_of_another_tree/subtree_of_another_tree_test.exs @@ -0,0 +1,94 @@ +defmodule LeetCodePractice.Solutions.SubtreeOfAnotherTreeTest do + use ExUnit.Case, async: true + + alias LeetCodePractice.Provisions.TreeNode + alias LeetCodePractice.Solutions.SubtreeOfAnotherTree + + test "Case 1 works" do + root = %TreeNode{ + val: 3, + left: %TreeNode{ + val: 4, + left: %TreeNode{ + val: 1, + left: nil, + right: nil + }, + right: %TreeNode{ + val: 2, + left: nil, + right: nil + } + }, + right: %TreeNode{ + val: 5, + left: nil, + right: nil + } + } + + sub_root = %TreeNode{ + val: 4, + left: %TreeNode{ + val: 1, + left: nil, + right: nil + }, + right: %TreeNode{ + val: 2, + left: nil, + right: nil + } + } + + assert SubtreeOfAnotherTree.call(root, sub_root) == true + end + + test "Case 2 works" do + root = %TreeNode{ + val: 3, + left: %TreeNode{ + val: 4, + left: %TreeNode{ + val: 1, + left: nil, + right: nil + }, + right: %TreeNode{ + val: 2, + left: %TreeNode{ + val: 0, + left: nil, + right: nil + }, + right: nil + } + }, + right: %TreeNode{ + val: 5, + left: nil, + right: nil + } + } + + sub_root = %TreeNode{ + val: 4, + left: %TreeNode{ + val: 1, + left: nil, + right: nil + }, + right: %TreeNode{ + val: 2, + left: nil, + right: nil + } + } + + assert SubtreeOfAnotherTree.call(root, sub_root) == false + end + + test "Extra case for 100% test coverage" do + assert SubtreeOfAnotherTree.call(nil, nil) == true + end +end