LeetCode in Kotlin

1048. Longest String Chain

Medium

You are given an array of words where each word consists of lowercase English letters.

wordA is a predecessor of wordB if and only if we can insert exactly one letter anywhere in wordA without changing the order of the other characters to make it equal to wordB.

A word chain is a sequence of words [word1, word2, ..., wordk] with k >= 1, where word1 is a predecessor of word2, word2 is a predecessor of word3, and so on. A single word is trivially a word chain with k == 1.

Return the length of the longest possible word chain with words chosen from the given list of words.

Example 1:

Input: words = [“a”,”b”,”ba”,”bca”,”bda”,”bdca”]

Output: 4

Explanation:: One of the longest word chains is [“a”,”ba”,”bda”,”bdca”].

Example 2:

Input: words = [“xbc”,”pcxbcf”,”xb”,”cxbc”,”pcxbc”]

Output: 5

Explanation: All the words can be put in a word chain [“xb”, “xbc”, “cxbc”, “pcxbc”, “pcxbcf”].

Example 3:

Input: words = [“abcd”,”dbqca”]

Output: 1

Explanation: The trivial word chain [“abcd”] is one of the longest word chains. [“abcd”,”dbqca”] is not a valid word chain because the ordering of the letters is changed.

Constraints:

Solution

class Solution {
    fun longestStrChain(words: Array<String>): Int {
        val lenStr = arrayOfNulls<MutableList<String>?>(20)
        for (word in words) {
            val len = word.length
            if (lenStr[len] == null) {
                lenStr[len] = ArrayList()
            }
            lenStr[len]!!.add(word)
        }
        val longest: MutableMap<String?, Int?> = HashMap()
        var max = 0
        for (s in words) {
            max = findLongest(s, lenStr, longest).coerceAtLeast(max)
        }
        return max
    }

    private fun findLongest(
        word: String,
        lenStr: Array<MutableList<String>?>,
        longest: MutableMap<String?, Int?>
    ): Int {
        if (longest.containsKey(word)) {
            return longest[word]!!
        }
        val len = word.length
        val words: List<String>? = lenStr[len + 1]
        if (words == null) {
            longest[word] = 1
            return 1
        }
        var max = 0
        var i: Int
        var j: Int
        for (w in words) {
            i = 0
            j = 0
            while (i < len && j - i <= 1) {
                if (word[i] == w[j++]) {
                    ++i
                }
            }
            if (j - i <= 1) {
                max = findLongest(w, lenStr, longest).coerceAtLeast(max)
            }
        }
        ++max
        longest[word] = max
        return max
    }
}