LeetCode 1639 -通过给定词典构造目标字符串的方案数


本文摘自网络,作者,侵删。

题目

题目链接

通过给定词典构造目标字符串的方案数

给你一个字符串列表 words 和一个目标字符串 target 。words 中所有字符串都 长度相同  。

你的目标是使用给定的 words 字符串列表按照下述规则构造 target :

  • 从左到右依次构造 target 的每一个字符。
  • 为了得到 target 第 i 个字符(下标从 0 开始),当 target[i] = words[j][k] 时,你可以使用 words 列表中第 j 个字符串的第 k 个字符。
  • 一旦你使用了 words 中第 j 个字符串的第 k 个字符,你不能再使用 words 字符串列表中任意单词的第 x 个字符(x <= k)。也就是说,所有单词下标小于等于 k 的字符都不能再被使用。
  • 请你重复此过程直到得到目标字符串 target 。

请注意 在构造目标字符串的过程中,你可以按照上述规定使用 words 列表中 同一个字符串 的 多个字符 。

请你返回使用 words 构造 target 的方案数。由于答案可能会很大,请对 109 + 7 取余 后返回。

示例:

输入:words = ["acca","bbbb","caca"], target = "aba"
输出:6
解释:总共有 6 种方法构造目标串。
"aba" -> 下标为 0 ("acca"),下标为 1 ("bbbb"),下标为 3 ("caca")
"aba" -> 下标为 0 ("acca"),下标为 2 ("bbbb"),下标为 3 ("caca")
"aba" -> 下标为 0 ("acca"),下标为 1 ("bbbb"),下标为 3 ("acca")
"aba" -> 下标为 0 ("acca"),下标为 2 ("bbbb"),下标为 3 ("acca")
"aba" -> 下标为 1 ("caca"),下标为 2 ("bbbb"),下标为 3 ("acca")
"aba" -> 下标为 1 ("caca"),下标为 2 ("bbbb"),下标为 3 ("caca")


输入:words = ["abba","baab"], target = "bab"
输出:4
解释:总共有 4 种不同形成 target 的方法。
"bab" -> 下标为 0 ("baab"),下标为 1 ("baab"),下标为 2 ("abba")
"bab" -> 下标为 0 ("baab"),下标为 1 ("baab"),下标为 3 ("baab")
"bab" -> 下标为 0 ("baab"),下标为 2 ("baab"),下标为 3 ("baab")
"bab" -> 下标为 1 ("abba"),下标为 2 ("baab"),下标为 3 ("baab")

提示:

  • 1 <= words.length <= 1000
  • 1 <= words[i].length <= 1000
  • words 中所有单词长度相同。
  • 1 <= target.length <= 1000
  • words[i]target 都仅包含小写英文字母。

解答

最优的解决方案是使用动态规划 dp ,但是为了更好的理解,首先使用递归进行解答

递归

  • 假设pre是当前的偏移值,idx是target的下标
  • 如果 idx >= len(target) 就说明是一个解, return 1
func helper(words []string, idx int, target string, pre int) int{
    const MOD = 1e9 + 7
    if idx >= len(target) {
        return 1
    }
    sum := 0
    for _, word := range words {
        for s := pre; s < len(word); s++ {
            // 如果当前字符和目标字符相匹配,则继续递归
            if c == target[idx] {
                sum += helper(words, idx + 1, target, s + 1)
            }
        }
    }
    return sum % MOD
}

func numWays(words []string, target string) int {
    return helper(words, 0, target 0)
}

动态规划

上述的递归,有很多重复的比较,如果将target出现在words的次数保存,那么将减少次数比较

  • 假设 cnt(i,j)target[j] 出现在words的第i列的次数
  • 假设 dp(i,j)target 从0~j时,使用words的0~i列的解答个数
  • dp(i, j) = dp(i-1, j-1) * cnt(i, j) + dp(i-1, j)

实际上,并不需要计算target[j]出现的次数,而是计算所有26个字母出现的次数

func numWays(words []string, target string) int {
    const MOD = 1e9 + 7
    cnts := make([][]int, len(words[0]))
    for i := range cnts {
        cnts[i] = make([]int, 26)
    }
    for _, word := range words {
        for i, char := range word {
            cnts[i][char-'a']++
        }
    }
    dp := make([][]int, len(words[0])+1)
    for i := range dp {
        dp[i] = make([]int, len(target)+1)
        dp[i][0] = 1
    }
    for i := 1; i <= len(words[0]); i++ {
        for j := 1; j <= len(target); j++ {
            dp[i][j] = (dp[i-1][j-1]*cnts[i-1][target[j-1]-'a'] + dp[i-1][j]) % int(MOD)
        }
    }
    return dp[len(words[0])][len(target)]
}

本文来自:Segmentfault

感谢作者:.container .card .information strong

查看原文:LeetCode 1639 -通过给定词典构造目标字符串的方案数

相关阅读 >>

Golang 时间的格式化格式的含义

Golang 时间相关格式化

Go-grpc-rest环境搭建

Go语言队列的链式表示和实现

手撸Golang 基本数据结构与算法 二叉查找树

Golang defer 特性姿势还是有必要了解下的!!!

[Go-linq]-Go的.net linq式查询方法

Gocn酷Go推荐】protobuf生成Go代码插件GoGo/protobuf

Golang 语言的标准库 log 包怎么使用?

手撸Golang 行为型设计模式 策略模式

更多相关阅读请进入《Go》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...