LeetCode in Kotlin

2135. Count Words Obtained After Adding a Letter

Medium

You are given two 0-indexed arrays of strings startWords and targetWords. Each string consists of lowercase English letters only.

For each string in targetWords, check if it is possible to choose a string from startWords and perform a conversion operation on it to be equal to that from targetWords.

The conversion operation is described in the following two steps:

  1. Append any lowercase letter that is not present in the string to its end.
    • For example, if the string is "abc", the letters 'd', 'e', or 'y' can be added to it, but not 'a'. If 'd' is added, the resulting string will be "abcd".
  2. Rearrange the letters of the new string in any arbitrary order.
    • For example, "abcd" can be rearranged to "acbd", "bacd", "cbda", and so on. Note that it can also be rearranged to "abcd" itself.

Return the number of strings in targetWords that can be obtained by performing the operations on any string of startWords.

Note that you will only be verifying if the string in targetWords can be obtained from a string in startWords by performing the operations. The strings in startWords do not actually change during this process.

Example 1:

Input: startWords = [“ant”,”act”,”tack”], targetWords = [“tack”,”act”,”acti”]

Output: 2

Explanation:

Note that “act” does exist in startWords, but we must append one letter to the string before rearranging it.

Example 2:

Input: startWords = [“ab”,”a”], targetWords = [“abc”,”abcd”]

Output: 1

Explanation:

Constraints:

Solution

@Suppress("NAME_SHADOWING")
class Solution {
    private lateinit var set: MutableSet<Int>

    private fun preprocess(words: Array<String>) {
        set = HashSet()
        for (word in words) {
            val bitMap = getBitMap(word)
            set.add(bitMap)
        }
    }

    private fun matches(bitMap: Int): Boolean {
        return set.contains(bitMap)
    }

    private fun getBitMap(word: String): Int {
        var result = 0
        for (element in word) {
            val position = element.code - 'a'.code
            result = result or (1 shl position)
        }
        return result
    }

    private fun addBit(bitMap: Int, c: Char): Int {
        var bitMap = bitMap
        val position = c.code - 'a'.code
        bitMap = bitMap or (1 shl position)
        return bitMap
    }

    private fun removeBit(bitMap: Int, c: Char): Int {
        var bitMap = bitMap
        val position = c.code - 'a'.code
        bitMap = bitMap and (1 shl position).inv()
        return bitMap
    }

    fun wordCount(startWords: Array<String>, targetWords: Array<String>): Int {
        if (startWords.isEmpty()) {
            return 0
        }
        if (targetWords.isEmpty()) {
            return 0
        }
        preprocess(startWords)
        var count = 0
        for (word in targetWords) {
            var bitMap = getBitMap(word)
            for (i in word.indices) {
                bitMap = removeBit(bitMap, word[i])
                if (i > 0) {
                    bitMap = addBit(bitMap, word[i - 1])
                }
                if (matches(bitMap)) {
                    count++
                    break
                }
            }
        }
        return count
    }
}