chore: split solutions by language

Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
Matej Focko 2023-06-02 17:19:02 +02:00
parent 078993071a
commit 333866d1bc
Signed by: mfocko
GPG key ID: 7C47D46246790496
131 changed files with 4 additions and 4 deletions

View 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>())
}

View 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)
}

View 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] }})
}
}

View 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"
}
}

View 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)
}

View 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()
*/

View 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
}
}

View 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
}

View 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()!!
}
}

View 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
}

View 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
)
}

View 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
}
}

View 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"
}
}
}

View 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
}
}

View 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()
}
}

View 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)
}

View 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())
}

View 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")))
}