From c04560ee74bca47e832c1fe6fab528294eda5e90 Mon Sep 17 00:00:00 2001 From: Danil M Date: Sat, 27 Sep 2025 06:17:04 -0400 Subject: [PATCH 1/2] add 652 and logic for creating tree --- .../main/java/com/github/contest/Execute.kt | 21 +++--- .../contest/binaryTree/BinaryTreeLeetcode.kt | 62 +++++++++++++-- .../com/github/contest/binaryTree/TreeNode.kt | 75 +++++++++++++++++++ 3 files changed, 143 insertions(+), 15 deletions(-) create mode 100644 contest/src/main/java/com/github/contest/binaryTree/TreeNode.kt diff --git a/contest/src/main/java/com/github/contest/Execute.kt b/contest/src/main/java/com/github/contest/Execute.kt index 0ad3222..75ec647 100644 --- a/contest/src/main/java/com/github/contest/Execute.kt +++ b/contest/src/main/java/com/github/contest/Execute.kt @@ -1,8 +1,9 @@ package com.github.contest -import com.github.contest.binaryTree.TreeNode -import com.github.contest.binaryTree.replaceValueInTree +import com.github.contest.binaryTree.findDuplicateSubtrees +import com.github.contest.binaryTree.printTree +import com.github.contest.binaryTree.toTreeNode import com.github.contest.math.numberOfPowerfulInt import com.github.contest.slidingWindow.customStructure.rabinKarpMultiPattern import com.github.contest.slidingWindow.customStructure.slidingWindowClassic @@ -15,18 +16,18 @@ import java.util.TreeMap */ fun main() { + val tree = listOf(1, 2, 3, 4, null, 2, 4, null, null, 4).toTreeNode() + tree.printTree() - // 5,4,9,1,10,null,7 - val root = TreeNode(5) - root?.left = TreeNode(4) - root?.right = TreeNode(9) - root.left?.left = TreeNode(1) - root?.left?.right = TreeNode(10) - root?.right?.right = TreeNode(7) + findDuplicateSubtrees(tree).apply { + this.forEach { + it.printTree() + } + } - replaceValueInTree(root).also { println(it) } } + class Example(val param: String) { // Primary constructor parameter init { println("init block: $param") // Can access param! diff --git a/contest/src/main/java/com/github/contest/binaryTree/BinaryTreeLeetcode.kt b/contest/src/main/java/com/github/contest/binaryTree/BinaryTreeLeetcode.kt index 8caa75b..1b86f7b 100644 --- a/contest/src/main/java/com/github/contest/binaryTree/BinaryTreeLeetcode.kt +++ b/contest/src/main/java/com/github/contest/binaryTree/BinaryTreeLeetcode.kt @@ -7,10 +7,6 @@ import kotlin.math.abs * 1261. Find Elements in a Contaminated Binary Tree */ -class TreeNode(var `val`: Int) { - var left: TreeNode? = null - var right: TreeNode? = null -} class FindElements(private val root: TreeNode?) { @@ -317,7 +313,7 @@ fun printTree(root: TreeNode?): List> { val rows = height(root) val col = (1 shl rows) - 1 val res = MutableList(rows) { _ -> - MutableList(col) { "" } + MutableList(col) { " " } } val rootPos = (col - 1) / 2 val queue = LinkedList>().apply { @@ -353,3 +349,59 @@ private fun height(root: TreeNode?): Int = when { root == null -> 0 else -> 1 + maxOf(height(root.left), height(root.right)) } + +/** + * 652. Find Duplicate Subtrees + */ + +fun findDuplicateSubtrees(root: TreeNode?): List { + root ?: return listOf() + + if (root.left == null && root.right == null) return listOf() + + val paths = mutableMapOf>() + val res = mutableListOf() + val queue = LinkedList().apply { + offer(root) + } + + while (queue.isNotEmpty()) { + val size = queue.size + + for (i in 0 until size) { + val node = queue.poll() + val path = serializeDuplicateSubTree(node) + if (paths.contains(path)) { + val stub = TreeNode(0) to 0 + paths[path] = paths.getOrDefault(path, stub).let { + it.copy(second = it.second + 1) + } + } else { + paths[path] = Pair(node, 1) + } + + node.left?.let { + queue.offer(it) + } + + node.right?.let { + queue.offer(it) + } + } + } + + for ((_, value) in paths) { + if (value.second > 1) { + res.add(value.first) + } + } + + return res + +} + +private fun serializeDuplicateSubTree(root: TreeNode?): String = when { + root == null -> "null" + else -> "#${root.`val`} , ${serialize(root?.left)} , ${serialize(root?.right)}" +} + diff --git a/contest/src/main/java/com/github/contest/binaryTree/TreeNode.kt b/contest/src/main/java/com/github/contest/binaryTree/TreeNode.kt new file mode 100644 index 0000000..e4f01f2 --- /dev/null +++ b/contest/src/main/java/com/github/contest/binaryTree/TreeNode.kt @@ -0,0 +1,75 @@ +package com.github.contest.binaryTree + +import java.util.LinkedList + +class TreeNode(var `val`: Int) { + var left: TreeNode? = null + var right: TreeNode? = null +} + +fun TreeNode?.printTree() { + if (this == null) println("null") + + val printedTree = printTree(this) + + printedTree.forEach { + it.joinToString(" ").also { level -> + println(level) + } + } +} + + +fun List.toTreeNode(): TreeNode? { + + val root = TreeNode(this.first()!!) + val queue = LinkedList().apply { + offer(root) + } + + var i = 1 + + while (queue.isNotEmpty() && i < size) { + val node = queue.poll() + + if (i < size && this[i] != null) { + node.left = TreeNode(this[i]!!) + queue.offer(node.left) + } + + i++ + + if (i < size && this[i] != null) { + node.right = TreeNode(this[i]!!) + queue.offer(node.right) + } + + i++ + } + + return root +} + +private fun List.validationTree(): Unit? { + if (isEmpty()) return null + if (first() == null) throw IllegalArgumentException("First Element Shouldn't be NULL") + + + for (i in 0 until size) { + + if (this[i] == null) { + + val leftChildIndex = 2 * i + 1 + val rightChildIndex = 2 * i + 2 + + if (leftChildIndex < size && this[leftChildIndex] != null) throw IllegalArgumentException( + "Left subTree shouldn't have child" + ) + if (rightChildIndex < size && this[rightChildIndex] != null) throw IllegalArgumentException( + "Right subTree shouldn't have child" + ) + } + } + + return Unit +} \ No newline at end of file From e9f4ae6f815906c6235844d435702b889e013d89 Mon Sep 17 00:00:00 2001 From: Danil M Date: Sat, 27 Sep 2025 07:15:50 -0400 Subject: [PATCH 2/2] add 652 alt sol + prod variant --- .../main/java/com/github/contest/Execute.kt | 6 +-- .../BinaryTreeAlternativeSolution.kt | 42 ++++++++++++++++++- .../binaryTree/BinaryTreeProdVariant.kt | 42 ++++++++++++++++++- 3 files changed, 85 insertions(+), 5 deletions(-) diff --git a/contest/src/main/java/com/github/contest/Execute.kt b/contest/src/main/java/com/github/contest/Execute.kt index 75ec647..88d6716 100644 --- a/contest/src/main/java/com/github/contest/Execute.kt +++ b/contest/src/main/java/com/github/contest/Execute.kt @@ -1,7 +1,7 @@ package com.github.contest -import com.github.contest.binaryTree.findDuplicateSubtrees +import com.github.contest.binaryTree.findDuplicateSubtreesProdVariant import com.github.contest.binaryTree.printTree import com.github.contest.binaryTree.toTreeNode import com.github.contest.math.numberOfPowerfulInt @@ -17,9 +17,9 @@ import java.util.TreeMap fun main() { val tree = listOf(1, 2, 3, 4, null, 2, 4, null, null, 4).toTreeNode() - tree.printTree() + //tree.printTree() - findDuplicateSubtrees(tree).apply { + findDuplicateSubtreesProdVariant(tree).apply { this.forEach { it.printTree() } diff --git a/contest/src/main/java/com/github/contest/binaryTree/BinaryTreeAlternativeSolution.kt b/contest/src/main/java/com/github/contest/binaryTree/BinaryTreeAlternativeSolution.kt index 179db2e..948a3ba 100644 --- a/contest/src/main/java/com/github/contest/binaryTree/BinaryTreeAlternativeSolution.kt +++ b/contest/src/main/java/com/github/contest/binaryTree/BinaryTreeAlternativeSolution.kt @@ -48,6 +48,46 @@ fun isSubtreeSerialization(root: TreeNode?, subRoot: TreeNode?): Boolean { fun serialize(root: TreeNode?): String { if (root == null) return "null" - // Use preorder traversal with markers return "#${root.`val`} ${serialize(root.left)} ${serialize(root.right)}" +} + +/** + * 652. Find Duplicate Subtrees + * Alternative Solution + * Using Serialize + Traverse + */ + +fun findDuplicateSubtreesOtherSolution(root: TreeNode?): List { + val result = mutableListOf() + val subtreeMap = mutableMapOf() // serialization -> count + serialize(root, subtreeMap, result) + return result +} + +private fun serialize( + node: TreeNode?, + subtreeMap: MutableMap, + result: MutableList +): String { + if (node == null) return "#" + + // Postorder serialization: left + right + root + val serial = buildString { + append(serialize(node.left, subtreeMap, result)) + append(",") + append(serialize(node.right, subtreeMap, result)) + append(",") + append(node.`val`) + } + + + val count = subtreeMap.getOrDefault(serial, 0) + subtreeMap[serial] = count + 1 + + + if (count == 1) { + result.add(node) + } + + return serial } \ No newline at end of file diff --git a/contest/src/main/java/com/github/contest/binaryTree/BinaryTreeProdVariant.kt b/contest/src/main/java/com/github/contest/binaryTree/BinaryTreeProdVariant.kt index 7df2394..9f6d86e 100644 --- a/contest/src/main/java/com/github/contest/binaryTree/BinaryTreeProdVariant.kt +++ b/contest/src/main/java/com/github/contest/binaryTree/BinaryTreeProdVariant.kt @@ -77,4 +77,44 @@ fun mergeTreesProdVariant(root1: TreeNode?, root2: TreeNode?): TreeNode? = when newRoot.right = mergeTreesProdVariant(root1?.right, root2?.right) newRoot } -} \ No newline at end of file +} + +/** + * 652. Find Duplicate Subtrees + * Prod Variant + * Using DFS + */ + +fun findDuplicateSubtreesProdVariant(root: TreeNode?): List { + val hashToTreeNode = mutableMapOf() + return buildList { + fun dfs(root: TreeNode?): String { + if (root == null) return "#" + + val hash = buildString { + append(root.`val`) + append(",") + append("${dfs(root.left)}") + append(",") + append("${dfs(root.right)}") + } + + add(hash to root) + hashToTreeNode[hash] = root + + return hash + } + dfs(root) + }.groupingBy { it.first } + .eachCount() + .toList() + .filter { it.second > 1 } + .let { freq -> + buildList { + freq.forEach { + add(hashToTreeNode[it.first]) + } + } + } + +}