LeetCode.387 字符串中的第一个唯一字符

216 阅读2分钟

这是我参与8月更文挑战的第25天,活动详情查看:8月更文挑战

题目描述:

387. 字符串中的第一个唯一字符 - 力扣(LeetCode) (leetcode-cn.com)

给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。

示例:

s = "leetcode"
返回 0

s = "loveleetcode"
返回 2

提示: 你可以假定该字符串只包含小写字母。

思路分析

哈希表

我们遍历2次字符串,第一次遍历记录每个元素的个数到哈希表

第二次遍历的时候从哈希表中对比,如果次数为1,则为答案。

AC代码

class Solution {
    fun firstUniqChar(s: String): Int {
        if (s.isEmpty()) return -1

        val map = mutableMapOf<Char, Int>()
        // 构建哈希表:字符及其出现的频率
        for (c in s) {
            map[c] = map.getOrDefault(c, 0) + 1
        }
        // 找到索引
        for (i in 0 until s.length) {
            if (map[s[i]] == 1) return i
        }

        return -1
    }
}

数组计数

哈希表涉及到计算hashcode,索引,扩容等会比较慢。

我们可以使用数组计数,因为题目中最后提示了下:你可以假定该字符串只包含小写字母。

AC代码

class Solution {
    fun firstUniqChar(s: String): Int {
        val chs = s.toCharArray()
        val map = IntArray(26)

        for (i in 0 until s.length) {
           val index = chs[i] - 'a'
           map[index]++
        }

        for (i in 0 until s.length) {
            val index = chs[i] - 'a';
            if (map[index] == 1) {
                return i;
            }
        }
        return -1;
    }
}

当然利用kotlin的高阶语法,我们可以写出更简介的代码

class Solution {
    fun firstUniqChar(s: String): Int = s.fold(IntArray(26)) { acc, c ->
        acc.also { it[c - 'a']++ }
    }.let { cnt ->
        s.indexOfFirst { cnt[it - 'a'] == 1 }
    }
}

总结

解题不难,但是追求时间复杂度,空间复杂度的话就会有点小挑战,有很多细节可以抓,比如用数组比哈希表快,但是用数组的2个解法中,提前转了char数组的又快那么一丢丢,总之接替容易,优化无止境。

参考

字符串中的第一个唯一字符 - 字符串中的第一个唯一字符 - 力扣(LeetCode) (leetcode-cn.com)

387. 字符串中的第一个唯一字符 - 字符串中的第一个唯一字符 - 力扣(LeetCode) (leetcode-cn.com)

387. 字符串中的第一个唯一字符(每日一题) - 字符串中的第一个唯一字符 - 力扣(LeetCode) (leetcode-cn.com)