LeetCode in Kotlin

3563. Lexicographically Smallest String After Adjacent Removals

Hard

You are given a string s consisting of lowercase English letters.

You can perform the following operation any number of times (including zero):

Return the lexicographically smallest string that can be obtained after performing the operations optimally.

Note: Consider the alphabet as circular, thus 'a' and 'z' are consecutive.

Example 1:

Input: s = “abc”

Output: “a”

Explanation:

Example 2:

Input: s = “bcda”

Output: “”

Explanation:

Example 3:

Input: s = “zdce”

Output: “zdce”

Explanation:

Constraints:

Solution

import kotlin.math.abs

class Solution {
    private fun checkPair(char1: Char, char2: Char): Boolean {
        val diffVal = abs(char1.code - char2.code)
        return diffVal == 1 || (char1 == 'a' && char2 == 'z') || (char1 == 'z' && char2 == 'a')
    }

    fun lexicographicallySmallestString(sIn: String): String {
        val nVal = sIn.length
        if (nVal == 0) {
            return ""
        }
        val remTable = Array<BooleanArray>(nVal) { BooleanArray(nVal) }
        var len = 2
        while (len <= nVal) {
            for (idx in 0..nVal - len) {
                val j = idx + len - 1
                if (checkPair(sIn[idx], sIn[j])) {
                    if (len == 2) {
                        remTable[idx][j] = true
                    } else {
                        if (remTable[idx + 1][j - 1]) {
                            remTable[idx][j] = true
                        }
                    }
                }
                if (remTable[idx][j]) {
                    continue
                }
                var pSplit = idx + 1
                while (pSplit < j) {
                    if (remTable[idx][pSplit] && remTable[pSplit + 1][j]) {
                        remTable[idx][j] = true
                        break
                    }
                    pSplit += 2
                }
            }
            len += 2
        }
        val dpArr: Array<String> = Array<String>(nVal + 1) { "" }
        dpArr[nVal] = ""
        for (idx in nVal - 1 downTo 0) {
            dpArr[idx] = sIn[idx].toString() + dpArr[idx + 1]
            for (kMatch in idx + 1..<nVal) {
                if (checkPair(sIn[idx], sIn[kMatch])) {
                    val middleVanishes: Boolean = if (kMatch - 1 < idx + 1) {
                        true
                    } else {
                        remTable[idx + 1][kMatch - 1]
                    }
                    if (middleVanishes) {
                        val candidate = dpArr[kMatch + 1]
                        if (candidate < dpArr[idx]) {
                            dpArr[idx] = candidate
                        }
                    }
                }
            }
        }
        return dpArr[0]
    }
}