字符串中的第一个唯一字符

标签: 队列 哈希表 字符串 计数

难度: Easy

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

示例 1:

输入: s = "leetcode"
输出: 0

示例 2:

输入: s = "loveleetcode"
输出: 2

示例 3:

输入: s = "aabb"
输出: -1

提示:

  • 1 <= s.length <= 105
  • s 只包含小写字母

Submission

运行时间: 42 ms

内存: 16.2 MB

class Solution(object):

    def firstUniqChar(self, s: str) -> int:
        # 先假设最小索引为最后的字符索引
        min_unique_char_index = len(s)

        # 已知字符串由小写字母构成,则遍历a-z
        for c in "abcdefghijklmnopqrstuvwxyz":
            i = s.find(c)
            # 分别从目标的字符串头和字符串尾查找对应字母的索引;如果两索引相等,则说明是单一字符
            if i != -1 and i == s.rfind(c):
                # 更新最新的最小索引
                min_unique_char_index = min(min_unique_char_index, i)

        # 如果返回值不为最后字符的索引,则返回最小索引值
        # 否则,根据题意,返回-1
        return min_unique_char_index if min_unique_char_index != len(s) else -1

Explain

题解采用的方法是遍历所有小写英文字母(从'a'到'z'),然后使用字符串的find()和rfind()方法来查找每个字符的首次出现和最后出现的位置。如果一个字符的首次出现位置和最后出现位置相同,这意味着该字符在字符串中只出现了一次。通过比较这些位置,可以找到第一个不重复字符的位置。该方法逐个字符地进行检查,而不是直接在原始字符串上进行多次迭代,以减少不必要的重复搜索。

时间复杂度: O(n)

空间复杂度: O(1)

class Solution(object):

    def firstUniqChar(self, s: str) -> int:
        # 初始化一个变量用于存储找到的最小唯一字符的索引,默认为字符串长度
        min_unique_char_index = len(s)

        # 遍历所有小写字母
        for c in "abcdefghijklmnopqrstuvwxyz":
            i = s.find(c)  # 在字符串s中找到字符c第一次出现的位置
            # 检查找到的位置是否是唯一的,即字符c的第一次和最后一次出现位置相同
            if i != -1 and i == s.rfind(c):
                # 更新最小索引
                min_unique_char_index = min(min_unique_char_index, i)

        # 检查是否找到了唯一字符,如果min_unique_char_index被更新过,则返回该索引,否则返回-1
        return min_unique_char_index if min_unique_char_index != len(s) else -1

Explore

遍历固定的26个英文字母而不是字符串中的每个字符,可以保持算法的时间复杂度为固定的O(26*n),即O(n),因为无论字符串长度如何,字符集大小固定为26。这种方法避免了在字符串中有大量重复字符时,多次迭代同一字符带来的性能损耗。此外,这种方法简化了逻辑,因为只需关注英文字母,而不需处理字符串中可能出现的非字母字符。

该方法确实考虑到了性能问题。使用find()和rfind()方法可以直接定位字符的第一次和最后一次出现位置,如果这两个位置相同,则证明字符不重复。即使字符串中包含大量重复字符,每个字符的查找仍然只进行两次(一次find和一次rfind),这比遍历整个字符串检查每个字符是否重复要高效。这种方法的时间复杂度主要由字符串的长度和固定的字符集大小决定,因此在大多数情况下都是有效的。

是的,该算法能够处理所有边界情况。对于长度为1的字符串,因为只有一个字符,find()和rfind()返回的索引必然相同,因此会正确返回该字符的索引。对于完全由相同字符组成的字符串,每个字符的find()和rfind()查找到的索引不会相同,因此这种情况下算法会返回-1,表示没有唯一字符。

使用字符串长度作为默认的min_unique_char_index值是一种有效的初始化策略,因为字符串索引是从0开始,最大索引值为字符串长度减1。设置初始值为字符串长度可以确保只有当找到一个有效的、更小的唯一字符索引时,才会更新这个变量。这种比较方式简化了逻辑判断,如果在遍历结束后min_unique_char_index值仍然等于字符串长度,则表示没有找到任何唯一字符,因此应返回-1。