LCP 69-Hello LeetCode!
力扣嘉年华同样准备了纪念品展位,参观者只需要集齐 helloleetcode 的 13 张字母卡片即可获得力扣纪念章。
在展位上有一些由字母卡片拼成的单词,words[i][j] 表示第 i 个单词的第 j 个字母。
你可以从这些单词中取出一些卡片,但每次拿取卡片都需要消耗游戏代币,规则如下: - 从一个单词中取一个字母所需要的代币数量,为该字母左边和右边字母数量之积
- 可以从一个单词中多次取字母,每个字母仅可被取一次 > 例如:从 example 中取出字母 a,需要消耗代币2*4=8,字母取出后单词变为 exmple; 再从中取出字母 m,需要消耗代币 2*3=6,字母取出后单词变为 exple;
请返回取得 helloleetcode 这些字母需要消耗代币的 最少 数量。如果无法取得,返回 -1。 注意: -
取出字母的顺序没有要求 - 取出的所有字母恰好可以拼成 helloleetcode 示例 1: >输入:words = ["hold","engineer","cost","level"] > >输出:5 > >解释:最优方法为: >从 hold 依次取出h、o、l、d, 代价均为 0 >从 engineer 依次取出第 1 个 e 与最后一个 e, 代价为 0 和5*1=5 >从 cost 取出 c、o、t, 代价均为 0 >从 level 依次取出 l、l、e、e,
代价均为 0 >所有字母恰好可以拼成 helloleetcode,因此最小的代价为 5 示例 2: >输入:words = ["hello","leetcode"] > >输出:0 提示: + n == words.length + m == words[i].length + 1 <= n <= 24 + 1 <= m <= 8 + words[i][j] 仅为小写字母
视频讲解 已出炉,欢迎点赞三连,在评论区分享你对这场力扣杯的看法~
记录关键思路,详细的说明见视频讲解。
- 用位运算表示字母选择情况,由于一个字母可以选多个,因此要对二进制「分区」,每个区域表示对应字母的个数。
- 写一个记忆化搜索,f(i,\textit{mask}) 表示从第 i 个单词开始选,已经选择的单词为 mask 时,后续消耗代币的最小值。枚举 words}[i] 的所有合法选择方案转移到 f(i+1,\textit{mask}’)。
- 因此需要预处理每个 words}[i] 的每种选择字母的方案所消耗的代币的最小值,由于字符串很短,直接写个爆搜即可。
1 | # (字母在二进制上的起始位置, 这个字母能选择的上限, 位掩码) |
1 | const keys = "elohtcd" |