Advent of Kotlin Solutions
Everything good must come to an end, it is time to end Advent of Kotlin 2021 as well. See how those problems could be solved.
Week 1: JSON stringify
Our first challenge, was to stringify an object representing JSON.
This is a typical exercise to practice using when
with type smart-casting. This pattern is really popular in Kotlin (sometimes referred as Kotlin pattern matching). So I expected implementing stringify
function as a single-expression function with when
and a separate handling for each child of the JsonElement
sealed class.
Now think, what should there be in each case.
JsonNull
is alwaysnull
.JsonBoolean
value just needs to be transformed toString
.JsonString
value just needs to be wrapped with quotes.JsonNumber
is a bit more tricky, because a value 1.0 should be presented as 1. This means, that such values need to be transformed to Int first. I decided to recognize numbers with no decimal part by chaching if they are changed byfloor
.JsonArray
is just a collection of elements of typeJsonElement
. Each of them should be stringified withstringify
function (so we use recursion). They should be separated with comma, and the array should start and end with box bracket. This is a perfect case for usingjoinToString
function.JsonObject
is quite similar, but each value has a name. SinceMap
does not havejoinToString
function, we first need to transform it toList
withtoList
(transformsMap<K, V>
toList<Pair<K, V>>
).
Week 1: Possible well-formed parentheses
The task is to create a function, that for a given n
, generates all combinations of n
well-formed pairs of parentheses. Here are a few usage examples:
There are planty of ways, how this problem can be solved. One might generate all possible combinations, and filter out those that are not correct. Another one might insert parenthesis at different positions. But the most efficient and simple solution I know is quite simple. Let's build possible strings character by character. At the beginning, we have a number of parentheses to open, and no opened ones. In such case, we need to place "(". Now we have one open parenthesis, and one less to open. If the number of parenthesis to open is bigger than zero, then we can place either "(" or ")". Otherwise, we need to close those that are opened with ")". All the possible combinations can be implemented recursively in the following way:
Week 2: Tree algorithms
This is a continuation of classic exercises to practive recursive thinking and using Kotlin pattern matching (when expression with smart-casting). My solution is not the fastest, but it is readable and presents the algorithm quite clearly.
Week 3: k-means clustering
k-means was a bit more complicated task, and figuring out the algorithm was part of it. Here is my solution:
Week 4: JSON parsing
Parsing JSON is not a simple task. The below implementation is not perfect, but covers the most essential functionalities. As you might analize, it is parsing elements recursively. A big problem is finding where an element ends. For instance, when you parse a content of an array, you cannot just separate string with comma, because each element might incluse a comma inside (it might be another array or an object). Solving this kind of problems is not easy, but also sharpens our minds. In my implementation, I also used many regexes.
All the solutions, together with passing unit tests, can be found on GitHub: