chore: unwrap one layer
Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
parent
4fcc0c57fd
commit
2351dfd0ee
180 changed files with 2 additions and 3 deletions
kt
binary-tree-inorder-traversal.ktbinary-tree-level-order-traversal.ktcheck-if-every-row-and-column-contains-all-numbers.ktconstruct-string-from-binary-tree.ktfirst-unique-character-in-a-string.ktiterator-for-combination.ktlargest-3-same-digit-number-in-string.ktlowest-common-ancestor-of-a-binary-search-tree.ktmax-area-of-island.ktmaximize-distance-to-closest-person.ktmaximum-units-on-a-truck.ktminimum-number-of-refueling-stops.ktminimum-time-visiting-all-points.ktpower-of-three.ktrichest-customer-wealth.ktroman-to-integer.ktsplit-array-into-consecutive-subsequences.ktsubstring-with-concatenation-of-all-words.ktunique-morse-code-words.ktvalidate-binary-search-tree.ktword-ladder-ii.kt
26
kt/binary-tree-inorder-traversal.kt
Normal file
26
kt/binary-tree-inorder-traversal.kt
Normal file
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* Example:
|
||||
* var ti = TreeNode(5)
|
||||
* var v = ti.`val`
|
||||
* Definition for a binary tree node.
|
||||
* class TreeNode(var `val`: Int) {
|
||||
* var left: TreeNode? = null
|
||||
* var right: TreeNode? = null
|
||||
* }
|
||||
*/
|
||||
class Solution {
|
||||
fun inorderTraversal(root: TreeNode?, values: MutableList<Int>): List<Int> {
|
||||
if (root == null) {
|
||||
return values
|
||||
}
|
||||
|
||||
inorderTraversal(root.left, values)
|
||||
values.add(root.`val`!!)
|
||||
inorderTraversal(root.right, values)
|
||||
|
||||
return values
|
||||
}
|
||||
|
||||
fun inorderTraversal(root: TreeNode?): List<Int>
|
||||
= inorderTraversal(root, mutableListOf<Int>())
|
||||
}
|
27
kt/binary-tree-level-order-traversal.kt
Normal file
27
kt/binary-tree-level-order-traversal.kt
Normal file
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* Example:
|
||||
* var ti = TreeNode(5)
|
||||
* var v = ti.`val`
|
||||
* Definition for a binary tree node.
|
||||
* class TreeNode(var `val`: Int) {
|
||||
* var left: TreeNode? = null
|
||||
* var right: TreeNode? = null
|
||||
* }
|
||||
*/
|
||||
class Solution {
|
||||
private fun levelOrder(root: TreeNode?, levels: MutableList<MutableList<Int>>, level: Int): MutableList<MutableList<Int>> {
|
||||
if (root == null) {
|
||||
return levels
|
||||
}
|
||||
|
||||
if (level + 1 > levels.size) {
|
||||
levels.add(mutableListOf<Int>())
|
||||
}
|
||||
|
||||
levels[level].add(root.`val`)
|
||||
levelOrder(root.left, levels, level + 1)
|
||||
return levelOrder(root.right, levels, level + 1)
|
||||
}
|
||||
|
||||
fun levelOrder(root: TreeNode?): List<List<Int>> = levelOrder(root, mutableListOf<MutableList<Int>>(), 0)
|
||||
}
|
13
kt/check-if-every-row-and-column-contains-all-numbers.kt
Normal file
13
kt/check-if-every-row-and-column-contains-all-numbers.kt
Normal file
|
@ -0,0 +1,13 @@
|
|||
class Solution {
|
||||
fun checkValid(matrix: Array<IntArray>): Boolean {
|
||||
val n = matrix.size
|
||||
val required = (1..n).toSet()
|
||||
|
||||
fun checkDimension(
|
||||
dimensions: Iterable<Iterable<Int>>
|
||||
): Boolean = dimensions.all { it.toSet() == required }
|
||||
|
||||
return checkDimension(matrix.map(IntArray::toList)) &&
|
||||
checkDimension((0 until n).map { x -> matrix.map { row -> row[x] }})
|
||||
}
|
||||
}
|
30
kt/construct-string-from-binary-tree.kt
Normal file
30
kt/construct-string-from-binary-tree.kt
Normal file
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* Example:
|
||||
* var ti = TreeNode(5)
|
||||
* var v = ti.`val`
|
||||
* Definition for a binary tree node.
|
||||
* class TreeNode(var `val`: Int) {
|
||||
* var left: TreeNode? = null
|
||||
* var right: TreeNode? = null
|
||||
* }
|
||||
*/
|
||||
class Solution {
|
||||
fun tree2str(root: TreeNode?): String {
|
||||
if (root == null) {
|
||||
return ""
|
||||
}
|
||||
|
||||
val value = root.`val`.toString()
|
||||
val left = "(${tree2str(root.left)})"
|
||||
val right = "(${tree2str(root.right)})"
|
||||
|
||||
|
||||
if (left == "()" && right == "()") {
|
||||
return value
|
||||
} else if (right == "()") {
|
||||
return "$value$left"
|
||||
}
|
||||
|
||||
return "$value$left$right"
|
||||
}
|
||||
}
|
26
kt/first-unique-character-in-a-string.kt
Normal file
26
kt/first-unique-character-in-a-string.kt
Normal file
|
@ -0,0 +1,26 @@
|
|||
class Solution {
|
||||
private data class Accumulator(val firstIndex: Int, var count: Int = 0) {
|
||||
fun add() {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
fun firstUniqChar(s: String): Int = s
|
||||
.foldIndexed(mutableMapOf<Char, Accumulator>()) { i, acc, c ->
|
||||
acc.getOrPut(c) { Accumulator(i) }.add()
|
||||
acc
|
||||
}
|
||||
.filterValues { it.count == 1 }
|
||||
.minByOrNull { (_, acc) -> acc.firstIndex }
|
||||
?.value
|
||||
?.firstIndex
|
||||
?: -1
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val s = Solution()
|
||||
|
||||
check(s.firstUniqChar("leetcode") == 0)
|
||||
check(s.firstUniqChar("loveleetcode") == 2)
|
||||
check(s.firstUniqChar("aabb") == -1)
|
||||
}
|
46
kt/iterator-for-combination.kt
Normal file
46
kt/iterator-for-combination.kt
Normal file
|
@ -0,0 +1,46 @@
|
|||
class CombinationIterator(val characters: String, val combinationLength: Int) {
|
||||
private var indices = (0 until combinationLength).toMutableList()
|
||||
|
||||
private fun nextCombination(index: Int) {
|
||||
// bump the current index
|
||||
indices[index]++
|
||||
|
||||
// we have gone through the whole string
|
||||
while (indices[index] == characters.length && index > 0) {
|
||||
// bump the previous index
|
||||
nextCombination(index - 1)
|
||||
|
||||
// set current index to previous + 1, since it must be the following one
|
||||
indices[index] = indices[index - 1] + 1
|
||||
}
|
||||
}
|
||||
|
||||
// By default bumping just the last index
|
||||
private fun nextCombination() = nextCombination(combinationLength - 1)
|
||||
|
||||
private fun getCombination(): String =
|
||||
indices.map { characters[it] }.joinToString(separator="")
|
||||
|
||||
fun next(): String {
|
||||
// construct the combination
|
||||
val combination = getCombination()
|
||||
|
||||
// bump the combination
|
||||
nextCombination()
|
||||
|
||||
return combination
|
||||
}
|
||||
|
||||
fun hasNext(): Boolean =
|
||||
indices.all {
|
||||
it < characters.length
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Your CombinationIterator object will be instantiated and called as such:
|
||||
* var obj = CombinationIterator(characters, combinationLength)
|
||||
* var param_1 = obj.next()
|
||||
* var param_2 = obj.hasNext()
|
||||
*/
|
14
kt/largest-3-same-digit-number-in-string.kt
Normal file
14
kt/largest-3-same-digit-number-in-string.kt
Normal file
|
@ -0,0 +1,14 @@
|
|||
class Solution {
|
||||
fun largestGoodInteger(num: String): String = num
|
||||
.asSequence()
|
||||
.windowed(3)
|
||||
.filter { s ->
|
||||
s[0] == s[1] && s[1] == s[2]
|
||||
}
|
||||
.map { window ->
|
||||
window.joinToString("")
|
||||
}
|
||||
.maxByOrNull { num ->
|
||||
num.toInt()
|
||||
} ?: ""
|
||||
}
|
37
kt/lowest-common-ancestor-of-a-binary-search-tree.kt
Normal file
37
kt/lowest-common-ancestor-of-a-binary-search-tree.kt
Normal file
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* Definition for a binary tree node.
|
||||
* class TreeNode(var `val`: Int = 0) {
|
||||
* var left: TreeNode? = null
|
||||
* var right: TreeNode? = null
|
||||
* }
|
||||
*/
|
||||
|
||||
class Solution {
|
||||
fun lowestCommonAncestor(root: TreeNode?, p: TreeNode?, q: TreeNode?): TreeNode? {
|
||||
var ancestor: TreeNode? = null
|
||||
var pTrack = root
|
||||
var qTrack = root
|
||||
|
||||
while (pTrack == qTrack && pTrack != null && qTrack != null) {
|
||||
ancestor = pTrack
|
||||
|
||||
if (pTrack!!.`val` == p!!.`val`) {
|
||||
return p
|
||||
} else if (p!!.`val` < pTrack!!.`val`) {
|
||||
pTrack = pTrack.left
|
||||
} else {
|
||||
pTrack = pTrack.right
|
||||
}
|
||||
|
||||
if (qTrack!!.`val` == q!!.`val`) {
|
||||
return q
|
||||
} else if (q!!.`val` < qTrack!!.`val`) {
|
||||
qTrack = qTrack.left
|
||||
} else {
|
||||
qTrack = qTrack.right
|
||||
}
|
||||
}
|
||||
|
||||
return ancestor
|
||||
}
|
||||
}
|
39
kt/max-area-of-island.kt
Normal file
39
kt/max-area-of-island.kt
Normal file
|
@ -0,0 +1,39 @@
|
|||
fun <A, B> product(xs: Sequence<A>, ys: Sequence<B>): Sequence<Pair<A, B>> =
|
||||
xs.flatMap { x -> ys.map { y -> x to y } }
|
||||
|
||||
fun <A, B> product(xs: Iterable<A>, ys: Iterable<B>): Sequence<Pair<A, B>> =
|
||||
product(xs.asSequence(), ys.asSequence())
|
||||
|
||||
class Solution {
|
||||
fun BFS(grid: Array<IntArray>, coords: Pair<Int, Int>): Int {
|
||||
val queue = ArrayDeque<Pair<Int, Int>>()
|
||||
queue.addLast(coords)
|
||||
|
||||
var size = 0
|
||||
while (!queue.isEmpty()) {
|
||||
val (y, x) = queue.removeFirst()
|
||||
if (grid[y][x] != 1) {
|
||||
continue
|
||||
}
|
||||
|
||||
for ((dy, dx) in sequenceOf(0 to 1, 1 to 0, 0 to -1, -1 to 0)) {
|
||||
if (!(y + dy in grid.indices) || !(x + dx in grid[y + dy].indices)) {
|
||||
continue
|
||||
} else if (grid[y + dy][x + dx] != 1) {
|
||||
continue
|
||||
}
|
||||
|
||||
queue.addLast(y + dy to x + dx)
|
||||
}
|
||||
|
||||
// mark it as done
|
||||
grid[y][x] = 0
|
||||
size++
|
||||
}
|
||||
|
||||
return size
|
||||
}
|
||||
|
||||
fun maxAreaOfIsland(grid: Array<IntArray>): Int =
|
||||
product(grid.indices, grid.first().indices).map { BFS(grid, it) }.max() ?: 0
|
||||
}
|
18
kt/maximize-distance-to-closest-person.kt
Normal file
18
kt/maximize-distance-to-closest-person.kt
Normal file
|
@ -0,0 +1,18 @@
|
|||
class Solution {
|
||||
private fun mapSeats(seats: IntArray): MutableList<Int> =
|
||||
seats.map { if (it == 1) 0 else Int.MAX_VALUE }.toMutableList()
|
||||
|
||||
fun maxDistToClosest(seats: IntArray): Int {
|
||||
val left: MutableList<Int> = mapSeats(seats)
|
||||
for (i in left.indices.drop(1).filter { left[it] != 0 }) {
|
||||
left[i] = left[i - 1] + 1
|
||||
}
|
||||
|
||||
val right: MutableList<Int> = mapSeats(seats)
|
||||
for (i in right.indices.reversed().drop(1).filter { right[it] != 0 }) {
|
||||
right[i] = right[i + 1] + 1
|
||||
}
|
||||
|
||||
return left.zip(right).map { (l, r) -> if (l < r) l else r }.max()!!
|
||||
}
|
||||
}
|
19
kt/maximum-units-on-a-truck.kt
Normal file
19
kt/maximum-units-on-a-truck.kt
Normal file
|
@ -0,0 +1,19 @@
|
|||
class Solution {
|
||||
data class BoxType(val boxes: Int, val units: Int)
|
||||
fun toBoxType(x: IntArray): BoxType = BoxType(x[0], x[1])
|
||||
|
||||
fun maximumUnits(boxTypes: Array<IntArray>, truckSize: Int): Int =
|
||||
boxTypes
|
||||
.map { toBoxType(it) }
|
||||
.sortedByDescending(BoxType::units)
|
||||
.fold(0 to 0) { acc, boxType ->
|
||||
if (acc.first < truckSize) {
|
||||
val count = minOf(truckSize - acc.first, boxType.boxes)
|
||||
|
||||
(acc.first + count) to (acc.second + count * boxType.units)
|
||||
} else {
|
||||
acc
|
||||
}
|
||||
}
|
||||
.second
|
||||
}
|
59
kt/minimum-number-of-refueling-stops.kt
Normal file
59
kt/minimum-number-of-refueling-stops.kt
Normal file
|
@ -0,0 +1,59 @@
|
|||
import java.util.PriorityQueue
|
||||
|
||||
class Solution {
|
||||
fun minRefuelStops(target: Int, startFuel: Int, stations: Array<IntArray>): Int {
|
||||
var maxReach = startFuel
|
||||
val availableRefuelling = PriorityQueue<Int>(reverseOrder())
|
||||
|
||||
var refuelled = 0
|
||||
var i = 0
|
||||
|
||||
while (maxReach < target) {
|
||||
while (i < stations.size && stations[i][0] <= maxReach) {
|
||||
// keep track of possible refuels
|
||||
availableRefuelling.add(stations[i][1])
|
||||
i++
|
||||
}
|
||||
|
||||
if (availableRefuelling.isEmpty()) {
|
||||
// no refuels are available and target has not been reached
|
||||
return -1
|
||||
}
|
||||
|
||||
|
||||
// refuel at least once in order to progress
|
||||
maxReach += availableRefuelling.poll()!!
|
||||
refuelled++
|
||||
}
|
||||
return refuelled
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val s = Solution()
|
||||
|
||||
check(s.minRefuelStops(1, 1, arrayOf()) == 0)
|
||||
check(s.minRefuelStops(100, 1, arrayOf(intArrayOf(10, 100))) == -1)
|
||||
check(
|
||||
s.minRefuelStops(
|
||||
100, 10, arrayOf(intArrayOf(10, 60), intArrayOf(20, 30), intArrayOf(30, 30), intArrayOf(60, 40))
|
||||
) == 2
|
||||
)
|
||||
check(
|
||||
s.minRefuelStops(
|
||||
1000, 299,
|
||||
arrayOf(
|
||||
intArrayOf(13, 21),
|
||||
intArrayOf(26, 115),
|
||||
intArrayOf(100, 47),
|
||||
intArrayOf(225, 99),
|
||||
intArrayOf(299, 141),
|
||||
intArrayOf(444, 198),
|
||||
intArrayOf(608, 190),
|
||||
intArrayOf(636, 157),
|
||||
intArrayOf(647, 255),
|
||||
intArrayOf(841, 123)
|
||||
)
|
||||
) == 4
|
||||
)
|
||||
}
|
8
kt/minimum-time-visiting-all-points.kt
Normal file
8
kt/minimum-time-visiting-all-points.kt
Normal file
|
@ -0,0 +1,8 @@
|
|||
class Solution {
|
||||
fun minTimeToVisitAllPoints(points: Array<IntArray>): Int =
|
||||
points.zip(points.drop(1)).sumOf { (a, b) ->
|
||||
val (ax, ay) = a
|
||||
val (bx, by) = b
|
||||
Math.max((ax - bx).absoluteValue, (ay - by).absoluteValue)
|
||||
}
|
||||
}
|
13
kt/power-of-three.kt
Normal file
13
kt/power-of-three.kt
Normal file
|
@ -0,0 +1,13 @@
|
|||
class Solution {
|
||||
fun isPowerOfThree(n: Int): Boolean {
|
||||
if (n < 1) {
|
||||
return false
|
||||
}
|
||||
|
||||
var x = n
|
||||
while (x % 3 == 0) {
|
||||
x /= 3
|
||||
}
|
||||
return x == 1
|
||||
}
|
||||
}
|
6
kt/richest-customer-wealth.kt
Normal file
6
kt/richest-customer-wealth.kt
Normal file
|
@ -0,0 +1,6 @@
|
|||
class Solution {
|
||||
fun maximumWealth(accounts: Array<IntArray>): Int =
|
||||
accounts.map { account ->
|
||||
account.sum()
|
||||
}.maxOrNull()!!
|
||||
}
|
62
kt/roman-to-integer.kt
Normal file
62
kt/roman-to-integer.kt
Normal file
|
@ -0,0 +1,62 @@
|
|||
class Solution {
|
||||
/**
|
||||
* Holds fixed mapping of roman numerals to their respective numeric value.
|
||||
*/
|
||||
private val values = mapOf(
|
||||
'I' to 1, 'V' to 5, 'X' to 10, 'L' to 50, 'C' to 100, 'D' to 500, 'M' to 1000
|
||||
)
|
||||
|
||||
/**
|
||||
* Represents an accumulator for right fold when turning roman numeral into an integer value.
|
||||
* @property sum Holds the current sum of the accumulator.
|
||||
* @property next Holds the value of the previous roman numeral digit.
|
||||
*/
|
||||
private data class Accumulator(val sum: Int = 0, val next: Int = 0) {
|
||||
/**
|
||||
* @param it Current roman numeral digit.
|
||||
* @return Sign that is to be used when modifying sum of the accumulator.
|
||||
*/
|
||||
private fun sign(it: Int): Int = when (next > it) {
|
||||
true -> -1
|
||||
false -> 1
|
||||
}
|
||||
|
||||
/**
|
||||
* @param it Currently processed roman numeral digit.
|
||||
* @return Correctly updated accumulator.
|
||||
*/
|
||||
fun update(it: Int): Accumulator = copy(sum = sum + sign(it) * it, next = it)
|
||||
}
|
||||
|
||||
fun romanToInt(s: String): Int = s
|
||||
.map { values[it]!! }
|
||||
.foldRight(Accumulator()) { it, acc ->
|
||||
acc.update(it)
|
||||
}
|
||||
.sum
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val s = Solution()
|
||||
|
||||
val tests = mapOf(
|
||||
"I" to 1,
|
||||
"II" to 2,
|
||||
"III" to 3,
|
||||
"IV" to 4,
|
||||
"V" to 5,
|
||||
"VI" to 6,
|
||||
"VII" to 7,
|
||||
"VIII" to 8,
|
||||
"IX" to 9,
|
||||
"X" to 10,
|
||||
"LVIII" to 58,
|
||||
"MCMXCIV" to 1994
|
||||
)
|
||||
|
||||
tests.forEach { (num, i) ->
|
||||
check(s.romanToInt(num) == i) {
|
||||
"$num: ${s.romanToInt(num)} == $i"
|
||||
}
|
||||
}
|
||||
}
|
37
kt/split-array-into-consecutive-subsequences.kt
Normal file
37
kt/split-array-into-consecutive-subsequences.kt
Normal file
|
@ -0,0 +1,37 @@
|
|||
class Solution {
|
||||
private fun getFrequencies(nums: IntArray): MutableMap<Int, Int> {
|
||||
val freqs = mutableMapOf<Int, Int>()
|
||||
|
||||
nums.forEach {
|
||||
freqs[it] = 1 + freqs.getOrDefault(it, 0)
|
||||
}
|
||||
|
||||
return freqs
|
||||
}
|
||||
|
||||
fun isPossible(nums: IntArray): Boolean {
|
||||
val frequencies = getFrequencies(nums)
|
||||
val sortedNumbers = frequencies.keys.toList().sorted()
|
||||
|
||||
sortedNumbers.forEach {
|
||||
while (frequencies[it]!! > 0) {
|
||||
var last = 0
|
||||
var j = it
|
||||
var k = 0
|
||||
|
||||
while (frequencies.getOrDefault(j, 0) >= last) {
|
||||
last = frequencies[j]!!
|
||||
frequencies[j] = frequencies[j]!! - 1
|
||||
|
||||
j++
|
||||
k++
|
||||
}
|
||||
if (k < 3) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
29
kt/substring-with-concatenation-of-all-words.kt
Normal file
29
kt/substring-with-concatenation-of-all-words.kt
Normal file
|
@ -0,0 +1,29 @@
|
|||
class Solution {
|
||||
private fun buildTable(words: Sequence<String>): Map<String, Int> {
|
||||
val table = mutableMapOf<String, Int>()
|
||||
|
||||
words.forEach {
|
||||
table.put(it, 1 + table.getOrElse(it) { 0 })
|
||||
}
|
||||
|
||||
return table
|
||||
}
|
||||
private fun buildTable(s: String, length: Int): Map<String, Int> =
|
||||
buildTable(s.chunked(length).asSequence())
|
||||
|
||||
fun findSubstring(s: String, words: Array<String>): List<Int> {
|
||||
val expectedFrequencies = buildTable(words.asSequence())
|
||||
val wordLen = words.first().length
|
||||
val windowSize = wordLen * words.size
|
||||
|
||||
return s
|
||||
.windowed(windowSize)
|
||||
.zip(s.indices)
|
||||
.filter { (window, _) ->
|
||||
val frequencies = buildTable(window, wordLen)
|
||||
frequencies == expectedFrequencies
|
||||
}
|
||||
.map { (_, idx) -> idx }
|
||||
.toList()
|
||||
}
|
||||
}
|
47
kt/unique-morse-code-words.kt
Normal file
47
kt/unique-morse-code-words.kt
Normal file
|
@ -0,0 +1,47 @@
|
|||
class Solution {
|
||||
val mapping = arrayOf(
|
||||
".-",
|
||||
"-...",
|
||||
"-.-.",
|
||||
"-..",
|
||||
".",
|
||||
"..-.",
|
||||
"--.",
|
||||
"....",
|
||||
"..",
|
||||
".---",
|
||||
"-.-",
|
||||
".-..",
|
||||
"--",
|
||||
"-.",
|
||||
"---",
|
||||
".--.",
|
||||
"--.-",
|
||||
".-.",
|
||||
"...",
|
||||
"-",
|
||||
"..-",
|
||||
"...-",
|
||||
".--",
|
||||
"-..-",
|
||||
"-.--",
|
||||
"--.."
|
||||
)
|
||||
|
||||
private fun charToMorse(c: Char): String = mapping[c - 'a']
|
||||
|
||||
fun uniqueMorseRepresentations(words: Array<String>): Int =
|
||||
words
|
||||
.map { word ->
|
||||
word.map { charToMorse(it) }.joinToString(separator = "")
|
||||
}
|
||||
.toSet()
|
||||
.size
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val s = Solution()
|
||||
|
||||
check(s.uniqueMorseRepresentations(arrayOf("gin", "zen", "gig", "msg")) == 2)
|
||||
check(s.uniqueMorseRepresentations(arrayOf("a")) == 1)
|
||||
}
|
26
kt/validate-binary-search-tree.kt
Normal file
26
kt/validate-binary-search-tree.kt
Normal file
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* Example:
|
||||
* var ti = TreeNode(5)
|
||||
* var v = ti.`val`
|
||||
* Definition for a binary tree node.
|
||||
* class TreeNode(var `val`: Int) {
|
||||
* var left: TreeNode? = null
|
||||
* var right: TreeNode? = null
|
||||
* }
|
||||
*/
|
||||
class Solution {
|
||||
private data class SpecialRange(val min: Int? = null, val max: Int? = null) {
|
||||
fun check(x: Int): Boolean =
|
||||
(min == null || x > min) && (max == null || x < max)
|
||||
}
|
||||
|
||||
private fun isValidBST(root: TreeNode?, range: SpecialRange): Boolean =
|
||||
when (root) {
|
||||
null -> true
|
||||
else -> range.check(root.`val`)
|
||||
&& isValidBST(root.left, range.copy(max=root.`val`))
|
||||
&& isValidBST(root.right, range.copy(min=root.`val`))
|
||||
}
|
||||
|
||||
fun isValidBST(root: TreeNode?): Boolean = isValidBST(root, SpecialRange())
|
||||
}
|
157
kt/word-ladder-ii.kt
Normal file
157
kt/word-ladder-ii.kt
Normal file
|
@ -0,0 +1,157 @@
|
|||
class Solution {
|
||||
private fun wordDifference(lhs: String, rhs: String): Int = lhs.zip(rhs).count { (l, r) -> l != r }
|
||||
|
||||
private enum class VertexState {
|
||||
Unvisited, Enqueued, Done
|
||||
}
|
||||
|
||||
private data class Vertex<T>(
|
||||
val label: T, val neighbours: MutableSet<Vertex<T>> = mutableSetOf()
|
||||
) {
|
||||
var distance: Int = Int.MAX_VALUE
|
||||
val parents: MutableSet<Vertex<T>> = mutableSetOf()
|
||||
var state: VertexState = VertexState.Unvisited
|
||||
private set
|
||||
|
||||
fun add(neighbour: Vertex<T>) {
|
||||
neighbours.add(neighbour)
|
||||
}
|
||||
|
||||
fun addParent(parent: Vertex<T>) {
|
||||
parents.add(parent)
|
||||
}
|
||||
|
||||
fun transition() {
|
||||
state = when (state) {
|
||||
VertexState.Unvisited -> VertexState.Enqueued
|
||||
VertexState.Enqueued -> VertexState.Done
|
||||
VertexState.Done -> error("Cannot transition further!")
|
||||
}
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = label.hashCode()
|
||||
override fun toString(): String = "$label(${neighbours.map { it.label.toString() }})"
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as Vertex<*>
|
||||
|
||||
if (label != other.label) return false
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
private class Graph<T> {
|
||||
private val vertices: MutableMap<T, Vertex<T>> = mutableMapOf()
|
||||
|
||||
fun addVertex(src: T, dst: T) {
|
||||
val u = vertices.getOrPut(src) { Vertex(src) }
|
||||
val v = vertices.getOrPut(dst) { Vertex(dst) }
|
||||
|
||||
u.add(v)
|
||||
}
|
||||
|
||||
fun addSymmetricVertex(src: T, dst: T) {
|
||||
addVertex(src, dst)
|
||||
addVertex(dst, src)
|
||||
}
|
||||
|
||||
private fun processVertex(queue: ArrayDeque<Vertex<T>>, u: Vertex<T>) {
|
||||
u.neighbours.forEach { v ->
|
||||
if (v.state == VertexState.Unvisited) {
|
||||
queue.addLast(v)
|
||||
|
||||
queue.last().distance = u.distance + 1
|
||||
queue.last().transition()
|
||||
} else if (u.distance + 1 != v.distance) {
|
||||
return@forEach
|
||||
}
|
||||
|
||||
v.addParent(u)
|
||||
}
|
||||
|
||||
u.transition()
|
||||
}
|
||||
|
||||
fun bfs(src: T, dst: T) {
|
||||
if (vertices[src] == null) {
|
||||
return
|
||||
}
|
||||
|
||||
val queue = ArrayDeque<Vertex<T>>()
|
||||
queue.addLast(vertices[src]!!)
|
||||
|
||||
queue.last().distance = 0
|
||||
queue.last().transition()
|
||||
|
||||
while (queue.isNotEmpty()) {
|
||||
val u = queue.removeFirst()
|
||||
if (u.label == dst) {
|
||||
break
|
||||
}
|
||||
|
||||
processVertex(queue, u)
|
||||
}
|
||||
}
|
||||
|
||||
fun parents(vertex: T): List<T> = vertices[vertex]?.parents?.map(Vertex<T>::label) ?: emptyList()
|
||||
|
||||
override fun toString(): String = vertices.toString()
|
||||
}
|
||||
|
||||
private fun constructGraph(src: String, vertices: List<String>): Graph<String> {
|
||||
val g = Graph<String>()
|
||||
|
||||
vertices
|
||||
.filter { wordDifference(src, it) == 1 }
|
||||
.forEach { g.addVertex(src, it) }
|
||||
|
||||
vertices.indices
|
||||
.flatMap { listOf(it).zip(it + 1 until vertices.size) }
|
||||
.map { (i, j) -> vertices[i] to vertices[j] }
|
||||
.filter { (lhs, rhs) -> wordDifference(lhs, rhs) == 1 }
|
||||
.forEach { (lhs, rhs) -> g.addSymmetricVertex(lhs, rhs) }
|
||||
|
||||
return g
|
||||
}
|
||||
|
||||
private fun constructPath(
|
||||
graph: Graph<String>, currentPath: MutableList<String>, paths: MutableList<MutableList<String>>
|
||||
): MutableList<MutableList<String>> {
|
||||
if (graph.parents(currentPath.last()).isEmpty()) {
|
||||
paths.add(currentPath.reversed().toMutableList())
|
||||
return paths
|
||||
}
|
||||
|
||||
for (parent in graph.parents(currentPath.last()).filter { !currentPath.contains(it) }) {
|
||||
currentPath.add(parent)
|
||||
constructPath(graph, currentPath, paths)
|
||||
currentPath.remove(parent)
|
||||
}
|
||||
|
||||
return paths
|
||||
}
|
||||
|
||||
fun findLadders(
|
||||
beginWord: String, endWord: String, wordList: List<String>
|
||||
): List<List<String>> {
|
||||
val graph = constructGraph(beginWord, wordList)
|
||||
graph.bfs(beginWord, endWord)
|
||||
return constructPath(graph, mutableListOf(endWord), mutableListOf()).filter { it.count() >= 2 }
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val s = Solution()
|
||||
|
||||
check(
|
||||
s.findLadders("hit", "cog", listOf("hot", "dot", "dog", "lot", "log", "cog")) == listOf(
|
||||
listOf("hit", "hot", "dot", "dog", "cog"), listOf("hit", "hot", "lot", "log", "cog")
|
||||
)
|
||||
)
|
||||
check(s.findLadders("hit", "cog", listOf("hot", "dot", "dog", "lot", "log")) == emptyList<List<String>>())
|
||||
check(s.findLadders("hot", "dog", listOf("hot", "dog")) == emptyList<List<String>>())
|
||||
check(s.findLadders("hot", "dog", listOf("hot", "dog", "dot")) == listOf(listOf("hot", "dot", "dog")))
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue