classSolution: defcountBits(self, num: int) -> List[int]: res = [] for i inrange(num + 1): cnt = 0 n = i while n > 0: cnt += n & 1 n = n >> 1 res.append(cnt) return res
classSolution: defminMoves(self, nums: List[int]) -> int: nums.sort() res = 0 for i inreversed(range(1, len(nums))): res += nums[i] - nums[0] return res
当然了,无论你想怎么去解决这道题目,首先还是要自己看懂题目。我们看看如何确定 t 在 s 中出现的次数。举个例子,假如 s = ababc,t = abc,那么很显然,t 在 s 出现了三次。然后我们来理一下,怎么统计。首先,我们把 t 的第一个字符 a,在 s 中标定,然后,是 b 标定,最后是 c,当 a 固定在第一个字符的时候,b 其实有两个选择。这两个选择的 b 都对应着唯一的 c,所以有两次,而 a,还有另一个选择,但是选那个 a 的时候,b,c 都只有唯一选择了,所以,总次数就是 3 次。
我上面描述的这个过程,就是一种最直观的统计策略。逐个标定 t 的每个字符,而且要穷尽每个字符的多个位置选择。这个就是一个比较明显的回溯过程。所以,很自然,我写出了回溯算法:
# 缓存 k = (p, q) v = self.mem.get(k, -1) if v > 0: return v if q == self.n - 1: v = self.s[p:].count(self.t[-1]) self.mem[k] = v return v total = 0 for i inrange(p, self.m): ifself.m - i >= self.n - q andself.s[i] == self.t[q]: total += self.dfs(i + 1, q + 1) self.mem[k] = total return total
对于这道手表的题目,题目要求点亮 num 盏灯,然后计算可能的时间数量。所以,我们可以把所有 num 盏灯都点亮,作为达成了目标的条件。第二,手表上,有代表小时的灯,1,2,4,8,四盏,以及代表分钟的灯1,2,4…… 等六盏灯,其实就相当于一共有 10 个位置,每次可以点亮一个。这么看,总状态空间,也就 2^10 个,就算都遍历了,也没多少……第三,我们要保存的状态,就是,点到第 i 盏灯的时候,表盘上所有的灯的亮灭情况。可以开动了:
classSolution: deffindNumOfValidWords(self, words: List[str], puzzles: List[str]) -> List[int]: # 初始化答案数组 result = {} for p in puzzles: result[p] = 0 sets = {}
for w in words: for p in puzzles:
if p in sets: p_set = sets[p] else: p_set = set([i for i in p]) sets[p] = p_set first_c = False c_c = True for c in w: #检查第一个字母 if c == p[0]: first_c = True if c notin p_set: c_c = False break if first_c and c_c: result[p] += 1 return [ result[key] for key in puzzles ]
好吧,只能看答案了。原来这道题目的套路叫“状态压缩”,我自己主动放弃的一个已知条件是,“没有顺序也没有频率的要求”,与其说是“放弃”,不如说是“不会用”。还有个条件是,word 和 puzzle 里只会出现小写字母。然后这题目就成了判断 word 里出现的字母,是不是都在 puzzle 里有,至于 word 里每个字母出现位置和次数都不重要了。
因为字母一共只有 26 个,所以我用一个 26 个 bit 的位图,就可以表达每个字母的有无了。一个整型是 32 位,正好可以用一个整数表达。于是,所有的 word 都可以表达成一个整数的位图。显然有些 word 虽然字面不一样,表达成位图后是一样的。于是我们可以用一个字典记录下来次数。
classSolution: defreverseVowels(self, s: str) -> str: ss = [ x for x in s ] i = 0 l = len(ss) j = l - 1 vowels = ['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'] while i < j: while i < l and ss[i] notin vowels: i += 1 while j > 0and ss[j] notin vowels: j -= 1
if i <= j: ss[i], ss[j] = ss[j], ss[i] i += 1 j -= 1 return"".join(ss)