Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions contest/src/main/java/com/github/contest/Execute.kt
Original file line number Diff line number Diff line change
@@ -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.findDuplicateSubtreesProdVariant
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
Expand All @@ -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)
findDuplicateSubtreesProdVariant(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!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<TreeNode?> {
val result = mutableListOf<TreeNode?>()
val subtreeMap = mutableMapOf<String, Int>() // serialization -> count
serialize(root, subtreeMap, result)
return result
}

private fun serialize(
node: TreeNode?,
subtreeMap: MutableMap<String, Int>,
result: MutableList<TreeNode?>
): 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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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?) {

Expand Down Expand Up @@ -317,7 +313,7 @@ fun printTree(root: TreeNode?): List<List<String>> {
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<Triple<TreeNode, Int, Int>>().apply {
Expand Down Expand Up @@ -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<TreeNode?> {
root ?: return listOf()

if (root.left == null && root.right == null) return listOf()

val paths = mutableMapOf<String, Pair<TreeNode, Int>>()
val res = mutableListOf<TreeNode?>()
val queue = LinkedList<TreeNode>().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)}"
}

Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,44 @@ fun mergeTreesProdVariant(root1: TreeNode?, root2: TreeNode?): TreeNode? = when
newRoot.right = mergeTreesProdVariant(root1?.right, root2?.right)
newRoot
}
}
}

/**
* 652. Find Duplicate Subtrees
* Prod Variant
* Using DFS
*/

fun findDuplicateSubtreesProdVariant(root: TreeNode?): List<TreeNode?> {
val hashToTreeNode = mutableMapOf<String, TreeNode>()
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])
}
}
}

}
75 changes: 75 additions & 0 deletions contest/src/main/java/com/github/contest/binaryTree/TreeNode.kt
Original file line number Diff line number Diff line change
@@ -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<Int?>.toTreeNode(): TreeNode? {

val root = TreeNode(this.first()!!)
val queue = LinkedList<TreeNode>().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<Int?>.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
}