https://leetcode.com/problems/number-of-ways-to-form-a-target-string-given-a-dictionary/
不容易想到的问题转化和dp的推导
个人解答
class Solution:def numWays(self, words: List[str], target: str) -> int:self.N = len(words[0])self.frequency = {}for ch in string.ascii_lowercase:self.frequency[ch] = [0] * self.N# record char frequencyfor w in words:for i, ch in enumerate(w):self.frequency[ch][i] += 1@functools.lru_cache(None)def f(targetIdx, wordsIdx):if targetIdx == len(target):return 1if wordsIdx == self.N:return 0res = 0# not choose char at current wordsIdxres += f(targetIdx, wordsIdx + 1)# choose current charch = target[targetIdx]if self.frequency[ch][wordsIdx] > 0:res += self.frequency[ch][wordsIdx] * f(targetIdx + 1, wordsIdx + 1)return resreturn f(0, 0) % (10**9 + 7)
题目分析
题目主要分为两步,单独每一步看都不算太难,但是整个题目不容易想到这两步。
1. 构建对应idx的频率表
其实题目条件给出的,所有word长度相同,便有这样的暗示,即,在只统计数量的情况下,选相同idx下不同word中的相同字母,是完全等效且与前后相互独立的!
因此,可以通过这一性质,简化输入,只保留在固定长度的word中,每个位置对应的各字母出现的频率,把一个二维问题,转化为了一维问题。
2. DP 0-1背包思想
0-1背包的思想可以用在很多的DP题目中,这道题便是很典型的应用,统计数量时,分两种情况讨论:
- 选择当前位置的字符
- 不选择当前位置的字符
如此经典的思想,几乎在一维DP中都会用到
除此之外,处理下特殊情况,就可以了
其它解法
题解里给出的是Top-Down的解法,得益于python的 lru_cache ,写起来比较直观,也不用显式memorize,当然也可以采用bottom-up的方式。
