题目描述
给一个单词表words, 一个字母表letters
当用letters中的字母可以拼出words中的某个单词时,可以获得得分,
得分是按照字母来算的,每个字母得分在score数组中
提示:
- 单词表长度不大于14
- words和letters中只包含小写字母
- words中每个单词只能使用一次
- 每个字母的使用不能超过其在letter中的个数
f1-枚举子集+状态压缩 |
基本分析
- 由于字母不能超过对应的个数,怎么判断需要用当前字母合成哪些单词并计算得分?没有捷径,就是枚举凑哪些单词出来
- 怎么枚举凑哪些单词?用一个二进制数来表示状态,state从低位到高位分别表示第i个word是不是凑出来
- 怎么判断当前方案是不是可行?
- 需要定义一个字典,表示当前状态使用的字符的情况,如果超过了,就返回0;如果没有超过就计算得分
- 怎么维护这个字典?i在(0,n)中遍历,如果当前位i是1,就把words[i]对应的字符累加进去
- 怎么统计这个状态对应的得分?遍历d,对每个ch-v,分别计算得分并最终求和
- 怎么获取最终结果?
枚举每个结果,取最大值
代码
class Solution:
def maxScoreWords(self, words: List[str], letters: List[str], score: List[int]) -> int:
# 统计每个单词对应的字母情况
words_cnt = [Counter(word) for word in letters]
letters_cnt = Counter(letters)
n = len(words)
@cache
def dfs(state):
d = dict()
for i in range(n):
if state >>i == 1: # 包含第i word
for ch, v in words_cnt[i].items():
d[ch] = d.get(ch, 0) + v
if d[ch] > letters_cnt[ch]:
return 0
ans = sum([score[ord(ch)-ord('a')] * v for ch, v in d.items()])
return ans
ans = max(dfs(i) for i in range(1, 1<<n))
return ans
复杂度
时间:待确定
空间:待确定
总结
- 这里每个单词都有两种可能,枚举了0-1<<n种可能
- 对每种可能计算能不能满足要求,能满足的计算得分
- 最终每种的得分取最大
- 还有比较快的f2-记忆化搜索+状态压缩的做法,待更新