判定字符是否唯一

标签: 位运算 哈希表 字符串 排序

难度: Easy

实现一个算法,确定一个字符串 s 的所有字符是否全都不同。

示例 1:

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

示例 2:

输入: s = "abc"
输出: true

限制:

  • 0 <= len(s) <= 100
  • s[i]仅包含小写字母
  • 如果你不使用额外的数据结构,会很加分。

Submission

运行时间: 19 ms

内存: 15.9 MB

class Solution:
    def isUnique(self, astr: str) -> bool:
        if len(astr)<=1: return True

        mark = 0
        for x in astr:
            move_bit = ord(x)-ord('a')
            if (mark & (1 << move_bit)) != 0:
                return False
            else:
                mark|= (1<<move_bit)
            
        return True

Explain

该题解采用了位运算技巧来检查字符串中是否有重复字符。首先,定义一个整数变量 `mark` 来作为位标记。这里每个位代表一个字符是否出现过。对于字符串中的每个字符,通过ASCII值减去字符'a'的ASCII值得到一个从0到25的值,表示该字符在字母表中的位置。这个值被用作位移量,通过左移操作生成一个只有一个位为1的二进制数。接着,使用与操作检查 `mark` 的相应位置是否已经为1,如果是,说明该字符已经出现过,直接返回false。如果不是,使用或操作更新 `mark` 的相应位置。如果整个字符串遍历完成没有发现重复字符,返回true。

时间复杂度: O(n)

空间复杂度: O(1)

class Solution:
    def isUnique(self, astr: str) -> bool:
        if len(astr) <= 1: return True  # 如果字符串长度为0或1,直接返回True

        mark = 0  # 初始化标记变量
        for x in astr:  # 遍历字符串中的每个字符
            move_bit = ord(x) - ord('a')  # 计算字符对应的位移值
            if (mark & (1 << move_bit)) != 0:  # 检查位标记是否已经被设置
                return False  # 如果已经设置,说明有重复字符,返回False
            else:
                mark |= (1 << move_bit)  # 设置对应的位标记
        
        return True  # 如果没有发现重复字符,返回True

Explore

位运算在这个算法中被选择使用主要因为它提供了一种空间效率极高的方式来追踪字符是否出现过。位运算只需一个32位或更少的整数即可表示所有小写字母,而使用哈希表或数组则需要更多的空间。此外,位运算的操作(与、或、左移)通常比哈希表的操作更快,且不需要处理哈希冲突,从而提高了算法的效率。

`mark & (1 << move_bit)`操作用于检查`mark`中对应于字符位置的位是否已经设置为1,这表示该字符已经出现过。这里,`(1 << move_bit)`将1左移`move_bit`位,生成一个只在对应位置有一个1的二进制数。与操作`&`用来测试`mark`中该位是否为1。如果结果不为0,表示在此之前相同字符的位已被设置,即字符已出现过,这样算法就能正确识别重复字符。

这种位运算方法只适用于字符串仅包含小写字母a到z的情况,因为它依赖于一个整数(通常是32位或64位)的位来标记这些字母。如果字符串包含其他字符,如大写字母、数字或符号,则无法使用这种方法,因为它超出了单个整数位所能表示的范围。对于包含更多不同字符的字符串,需要使用其他数据结构如哈希表或数组来追踪字符出现情况。