LeetCode 49. Group Anagrams(群组错位词)

210 阅读2分钟

leetcode.com/problems/gr…

Discuss:www.cnblogs.com/grandyang/p…

Given an array of strings strs, group the anagrams together. You can return the answer in any order.

An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.

Example 1:

Input: strs = ["eat","tea","tan","ate","nat","bat"]
Output: [["bat"],["nat","tan"],["ate","eat","tea"]]

Example 2:

Input: strs = [""]
Output: [[""]]

Example 3:

Input: strs = ["a"]
Output: [["a"]]

Constraints:

  • 1 <= strs.length <= 104

  • 0 <= strs[i].length <= 100

  • strs[i] consists of lower-case English letters.

解法一:

这道题让我们群组给定字符串集中所有的错位词,所谓的错位词就是两个字符串中字母出现的次数都一样,只是位置不同,比如 abc,bac, cba 等它们就互为错位词,那么如何判断两者是否是错位词呢,可以发现如果把错位词的字符顺序重新排列,那么会得到相同的结果,所以重新排序是判断是否互为错位词的方法,由于错位词重新排序后都会得到相同的字符串,以此作为 key,将所有错位词都保存到字符串数组中,建立 key 和其隶属的错位词集合之间的映射。最后 Map 中的 value 集合就是我们要的结果。

class Solution {
    fun groupAnagrams(strs: Array<String>): List<List<String>> {
        if (strs.size == 1) {
            return mutableListOf(strs.toList())
        }

        val result: MutableList<List<String>> = mutableListOf()
        val map = mutableMapOf<String, MutableList<String>>()

        strs.forEach {
            // kotlin 字符串排序,需要将 string 转为 charArray,然后调用 sorted() 方法,最后再调用 joinToString("") 方法转为 string
            val strArray = it.toCharArray()
            val sortStr = strArray.sorted().joinToString("")
            if (map.containsKey(sortStr)) {
                val valueList = map[sortStr]
                valueList?.add(it)
                map[sortStr] = valueList ?: mutableListOf()
            } else {
                val valueList = mutableListOf<String>()
                valueList.add(it)
                map[sortStr] = valueList
            }
        }

        map.values.forEach {
            result.add(it)
        }
        return result
    }
}

解法二:

还可以建立 key 和当前的不同的错位词集合个数之间的映射,这样可以避免最后再将 HashMap 中的集合拷贝到结果 result 中。当检测到当前的单词不在 HashMap 中,此时知道这个单词将属于一个新的错位词集合,所以将其映射为当前的错位词集合的个数,然后在 res 中新增一个空集合,这样就可以通过其映射值,直接找到新的错位词集合的位置,从而将新的单词存入结果 result 中。

class Solution {
    fun groupAnagrams(strs: Array<String>): List<List<String>> {
        if (strs.size == 1) {
            return mutableListOf(strs.toList())
        }

        val result: MutableList<MutableList<String>> = mutableListOf()

        val map = mutableMapOf<String, Int>()

        strs.forEach {
            // kotlin 字符串排序,需要将 string 转为 charArray,然后调用 sorted() 方法,最后再调用 joinToString("") 方法转为 string
            val strArray = it.toCharArray()
            val sortStr = strArray.sorted().joinToString("")
            if (map.containsKey(sortStr)) {
                val index = map[sortStr]
                val valueList = result[index!!]
                valueList.add(it)
            } else {
                val valueList = mutableListOf<String>()
                valueList.add(it)
                result.add(valueList)
                map[sortStr] = result.lastIndex
            }
        }

        return result
    }
}

解法三:

下面这种解法没有用到排序,用一个大小为 26 的 int 数组来统计每个单词中字符出现的次数,然后将 int 数组转为一个唯一的字符串,跟字符串数组进行映射,这样就不用给字符串排序了。

class Solution {
    fun groupAnagrams(strs: Array<String>): List<List<String>> {
        if (strs.size == 1) {
            return mutableListOf(strs.toList())
        }

        val result: MutableList<List<String>> = mutableListOf()
        val map = mutableMapOf<String, MutableList<String>>()

        strs.forEach { str ->
            val count = IntArray(26)
            for (i in 0 until 26) {
                count[i] = 0
            }
            str.forEach { char ->
                count[char - 'a']++
            }

            val key = StringBuilder()
            count.withIndex().forEach forEach2@{
                if (it.value == 0) {
                    return@forEach2
                }

                val char: Char = 'a'.plus(it.index)
                key.append((char))
                key.append(it.value)
            }
            
            val keyStr = key.toString()
            if (map.containsKey(keyStr)) {
                val valueList = map[keyStr]
                valueList?.add(str)
                map[keyStr] = valueList ?: mutableListOf()
            } else {
                val valueList = mutableListOf<String>()
                valueList.add(str)
                map[keyStr] = valueList
            }
        }

        map.values.forEach {
            result.add(it)
        }

        return result
    }
}