难度: Hard
Submission
运行时间: 68 ms
内存: 16.3 MB
class Solution: def minAbbreviation(self, target: str, dictionary: List[str]) -> str: ans = None mmin = None def getAbbr(mask, target): ans = '' num = 0 prev = None for i in range(len(target)): if mask & (1 << i): if prev != None: ans += str(i - prev) num += 1 prev = None ans += target[i] num += 1 else: if prev == None: prev = i if prev: ans += str(len(target) - prev) num += 1 return ans, num masks = set() for word in dictionary: if len(target) == len(word): mask = 0 for i in range(len(target)): if target[i] != word[i]: mask += (1 << i) masks.add(mask) if len(masks) == 0: return str(len(target)) for i in range(2 ** len(target)): if all(i & mask > 0 for mask in masks): abbr, length = getAbbr(i, target) if ans == None or length < mmin: ans = abbr mmin = length return ans
Explain
该题解使用位掩码来枚举target字符串的所有可能的缩写形式。对于字典中的每个单词,计算它与target的位掩码差异,并将差异掩码存储在一个集合中。然后枚举target的所有可能的位掩码,检查每个掩码是否能够区分target和字典中的所有单词。在所有有效的掩码中,选择对应的缩写长度最短的那个作为最终答案。
时间复杂度: O(mn + m2^n)
空间复杂度: O(m + n)
class Solution: def minAbbreviation(self, target: str, dictionary: List[str]) -> str: ans = None mmin = None def getAbbr(mask, target): ans = '' num = 0 prev = None for i in range(len(target)): if mask & (1 << i): if prev != None: ans += str(i - prev) num += 1 prev = None ans += target[i] num += 1 else: if prev == None: prev = i if prev: ans += str(len(target) - prev) num += 1 return ans, num # 生成字典中单词的差异掩码 masks = set() for word in dictionary: if len(target) == len(word): mask = 0 for i in range(len(target)): if target[i] != word[i]: mask += (1 << i) masks.add(mask) # 如果字典为空,直接返回target的长度作为缩写 if len(masks) == 0: return str(len(target)) # 枚举target的所有可能的位掩码 for i in range(2 ** len(target)): # 检查当前掩码是否能够区分target和字典中的所有单词 if all(i & mask > 0 for mask in masks): abbr, length = getAbbr(i, target) if ans == None or length < mmin: ans = abbr mmin = length return ans
Explore
在题解中,位掩码是一种技巧,用来表示字符串的每个字符是否被省略或保留。每个位(0或1)代表一个字符:'1'表示保留字符,'0'表示省略字符。例如,对于字符串'target',掩码'101010'(二进制表示)意味着保留第1、3、5个字符,省略第2、4、6个字符,从而形成缩写。枚举所有可能的位掩码等同于枚举target的所有可能缩写形式。通过对0到2^len(target)-1的所有整数进行循环,我们可以生成所有可能的掩码,并用这些掩码来构建target的每一种缩写形式。
条件`i & mask > 0`确保掩码`i`在与字典中每个单词对应的掩码`mask`进行按位与操作后,结果不为零。这意味着至少存在一个位置,在该位置上,target和字典中的单词在掩码`i`中是被保留的(即对应位是1),而在单词掩码`mask`中是不同的(单词在该位置的字符与target不同)。这保证了掩码`i`能够区分target和字典中的该单词。更直观的理解是:如果掩码`i`至少在一个与字典单词不同的字符位置上为1,那么这个掩码就能帮助区分target和该字典单词。
在`getAbbr`函数中,`prev`变量用来记录上一个被省略字符的位置。当遇到一个要保留的字符时(即掩码在该位置是1),如果`prev`不为空(即之前有省略的字符),则计算从`prev`位置到当前字符位置之间的字符数,这个数值将被添加到缩写中。例如,如果`prev`是2,当前位置是5,那么在缩写中添加'3'表示这两个位置之间省略了3个字符。此后,`prev`被重置为null,直到遇到下一个省略的字符序列,再次开始计数。如果`prev`非空且遍历完所有字符,还需要添加从`prev`到字符串末尾的省略字符数目。