这是我参与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)