LeetCode in Kotlin

1096. Brace Expansion II

Hard

Under the grammar given below, strings can represent a set of lowercase words. Let R(expr) denote the set of words the expression represents.

The grammar can best be understood through simple examples:

Formally, the three rules for our grammar:

Given an expression representing a set of words under the given grammar, return the sorted list of words that the expression represents.

Example 1:

Input: expression = “{a,b}{c,{d,e}}”

Output: [“ac”,”ad”,”ae”,”bc”,”bd”,”be”]

Example 2:

Input: expression = “{ {a,z},a{b,c},{ab,z}}”

Output: [“a”,”ab”,”ac”,”z”]

Explanation: Each distinct word is written only once in the final answer.

Constraints:

Solution

class Solution {
    fun braceExpansionII(expression: String): List<String> {
        val res = flatten(expression)
        val sorted: MutableList<String> = ArrayList(res)
        sorted.sort()
        return sorted
    }

    private fun flatten(expression: String): Set<String> {
        val res: MutableSet<String> = HashSet()
        // A temp set to store cartesian product results.
        var curSet: MutableSet<String> = HashSet()
        var idx = 0
        while (idx < expression.length) {
            if (expression[idx] == '{') {
                // end will be the index of matching "}"
                val end = findClosingBrace(expression, idx)
                val set = flatten(expression.substring(idx + 1, end))
                curSet = concatenateSet(curSet, set)
                idx = end + 1
            } else if (Character.isLowerCase(expression[idx])) {
                // Create set with single element
                val set: Set<String> = HashSet(
                    listOf(
                        expression[idx].toString()
                    )
                )
                curSet = concatenateSet(curSet, set)
                idx++
            } else if (expression[idx] == ',') {
                res.addAll(curSet)
                curSet.clear()
                idx++
            }
        }
        // Don't forget!
        res.addAll(curSet)
        return res
    }

    private fun concatenateSet(set1: Set<String>, set2: Set<String>): MutableSet<String> {
        if (set1.isEmpty() || set2.isEmpty()) {
            return if (set2.isNotEmpty()) HashSet(set2) else HashSet(set1)
        }
        val res: MutableSet<String> = HashSet()
        for (s1 in set1) {
            for (s2 in set2) {
                res.add(s1 + s2)
            }
        }
        return res
    }

    private fun findClosingBrace(expression: String, start: Int): Int {
        var count = 0
        var idx = start
        while (idx < expression.length) {
            if (expression[idx] == '{') {
                count++
            } else if (expression[idx] == '}') {
                count--
            }
            if (count == 0) {
                break
            }
            idx++
        }
        return idx
    }
}