Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >2025-04-23:形成目标字符串需要的最少字符串数Ⅱ。用go语言,给定一个字符串数组 words 和一个目标字符串 targ

2025-04-23:形成目标字符串需要的最少字符串数Ⅱ。用go语言,给定一个字符串数组 words 和一个目标字符串 targ

作者头像
福大大架构师每日一题
发布于 2025-04-23 01:35:45
发布于 2025-04-23 01:35:45
4800
代码可运行
举报
运行总次数:0
代码可运行

2025-04-23:形成目标字符串需要的最少字符串数Ⅱ。用go语言,给定一个字符串数组 words 和一个目标字符串 target。

如果某个字符串 x 是数组 words 中任意字符串的前缀,则称 x 是一个有效字符串。

现在希望通过拼接若干个有效字符串,组成目标字符串 target。请计算完成这个拼接所需的最少字符串数量,若无法拼接出 target,则返回 -1。

1 <= words.length <= 100。

1 <= words[i].length <= 5 * 10000。

输入确保 sum(words[i].length) <= 100000。

words[i] 只包含小写英文字母。

1 <= target.length <= 5 * 10000。

target 只包含小写英文字母。

输入: words = ["abc","aaaaa","bcdef"], target = "aabcdabc"。

输出: 3。

解释:

target 字符串可以通过连接以下有效字符串形成:

words[1] 的长度为 2 的前缀,即 "aa"。

words[2] 的长度为 3 的前缀,即 "bcd"。

words[0] 的长度为 3 的前缀,即 "abc"。

题目来自leetcode3292。

解决思路

  1. 1. 预处理阶段
    • • 对于目标字符串 target 的每一个位置 i,我们需要知道从 words 中所有字符串的前缀中,能够覆盖 target 的前 i 个字符的最长前缀长度。这可以通过 KMP 算法的前缀函数(prefix function)来实现。
    • • 具体来说,对于 words 中的每一个字符串 word,我们计算 word + "#" + target 的前缀函数数组 pi。这样,pi 数组的后半部分(即 target 的部分)会告诉我们 word 的前缀与 target 的各个子串的最长匹配长度。
    • • 对于 target 的每一个位置 i,我们记录所有 words 中字符串的前缀能够覆盖 targeti 个字符的最长长度 back[i]
  2. 2. 动态规划阶段
    • • 我们使用动态规划数组 dp,其中 dp[i] 表示构造 target 的前 i 个字符所需的最少有效字符串数量。
    • • 初始化时,dp[0] = 0(空字符串不需要任何有效字符串),其余 dp[i] 初始化为一个很大的值(表示不可达)。
    • • 对于 target 的每一个位置 i,我们利用预处理阶段得到的 back[i] 来更新 dp[i + 1]。具体来说,dp[i + 1] = min(dp[i + 1], dp[i + 1 - back[i]] + 1)
    • • 如果在动态规划过程中发现某个 dp[i] 的值超过了 target 的长度,说明无法构造 target,直接返回 -1。
  3. 3. 结果提取
    • • 最终 dp[n] 的值就是构造 target 所需的最少有效字符串数量。如果 dp[n] 仍然是初始化的很大值,说明无法构造 target,返回 -1。

具体步骤

  1. 1. 计算 back 数组
    • • 对于 words 中的每一个字符串 word,计算 word + "#" + target 的前缀函数 pi
    • • 对于 target 的每一个位置 iback[i] 是所有 words 中字符串的前缀函数在 target 部分(即 pi[m + 1 + i],其中 mword 的长度)的最大值。
  2. 2. 动态规划填充 dp 数组
    • • 初始化 dp[0] = 0,其余 dp[i] = ∞
    • • 对于 i0n - 1
      • • 如果 back[i] == 0,说明无法从 words 中找到一个前缀覆盖 target 的前 i + 1 个字符,跳过。
      • • 否则,dp[i + 1] = min(dp[i + 1], dp[i + 1 - back[i]] + 1)
      • • 如果 dp[i + 1] > n,直接返回 -1。
  3. 3. 返回结果
    • • 如果 dp[n] 仍然是 ,返回 -1;否则返回 dp[n]

时间复杂度和空间复杂度

  • 时间复杂度
    • • 预处理阶段:对于每一个 word,计算word + "#" + target的前缀函数的时间复杂度为O(m + n),其中mword的长度,ntarget的长度。由于sum(words[i].length) <= 100000,预处理阶段的总时间复杂度为O(sum(m) + k * n),其中kwords的数量。由于k <= 100,可以简化为O(sum(m) + n)
    • • 动态规划阶段:填充 dp 数组的时间复杂度为 O(n)
    • • 总时间复杂度:O(sum(m) + n)
  • 空间复杂度
    • back 数组:O(n)
    • dp 数组:O(n)
    • • 前缀函数 piO(m + n)(临时空间,可以复用)。
    • • 总空间复杂度:O(n + m)(其中 m 是最大的 word 长度)。

Go完整代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
    "fmt"
    "math"
)

func minValidStrings(words []string, target string)int {
    prefixFunction := func(word, target string) []int {
        s := word + "#" + target
        n := len(s)
        pi := make([]int, n)
        for i := 1; i < n; i++ {
            j := pi[i-1]
            for j > 0 && s[i] != s[j] {
                j = pi[j-1]
            }
            if s[i] == s[j] {
                j++
            }
            pi[i] = j
        }
        return pi
    }

    n := len(target)
    back := make([]int, n)
    for _, word := range words {
        pi := prefixFunction(word, target)
        m := len(word)
        for i := 0; i < n; i++ {
            back[i] = int(math.Max(float64(back[i]), float64(pi[m+1+i])))
        }
    }

    dp := make([]int, n+1)
    for i := 1; i <= n; i++ {
        dp[i] = int(1e9)
    }
    for i := 0; i < n; i++ {
        dp[i+1] = dp[i+1-back[i]] + 1
        if dp[i+1] > n {
            return-1
        }
    }
    return dp[n]
}

func main() {
    words := []string{"abc", "aaaaa", "bcdef"}
    target := "aabcdabc"
    results := minValidStrings(words, target)
    fmt.Println(results)
}

Python完整代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# -*-coding:utf-8-*-

defminValidStrings(words, target):
    n = len(target)
    if n == 0:
        return0

    defprefix_function(word, target_str):
        s = word + '#' + target_str
        pi = [0] * len(s)
        for i inrange(1, len(s)):
            j = pi[i-1]
            while j > 0and s[i] != s[j]:
                j = pi[j-1]
            if s[i] == s[j]:
                j += 1
            pi[i] = j
        return pi

    back = [0] * n
    for word in words:
        m = len(word)
        if m == 0:
            continue
        pi = prefix_function(word, target)
        for i inrange(n):
            pos = m + 1 + i
            current_pi = pi[pos] if pos < len(pi) else0
            if current_pi > back[i]:
                back[i] = current_pi

    dp = [float('inf')] * (n + 1)
    dp[0] = 0
    for i inrange(n):
        k = back[i]
        prev = (i + 1) - k
        if prev < 0:
            return -1
        if dp[prev] + 1 < dp[i+1]:
            dp[i+1] = dp[prev] + 1
        if dp[i+1] > n:
            return -1

    return dp[n] if dp[n] != float('inf') else -1

# 示例测试
if __name__ == "__main__":
    words = ["abc", "aaaaa", "bcdef"]
    target = "aabcdabc"
    print(minValidStrings(words, target))  
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-04-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 福大大架构师每日一题 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
搞定大厂算法面试之leetcode精讲20.字符串
方法1.截取字符串,循环字符串,遇到#就截掉最后一个字符,循环完毕之后,最后比较两个去除掉#退格之后的字符串是否相等,时间复杂度O(m+n),m、n是两个字符串的长度。空间复杂度O(1)
全栈潇晨
2021/12/04
7220
2024-10-26:最长公共后缀查询。用go语言,给定两个字符串数组 wordsContainer 和 wordsQuery,
2024-10-26:最长公共后缀查询。用go语言,给定两个字符串数组 wordsContainer 和 wordsQuery,要对每个 wordsQuery[i] 找到一个与其有最长公共后缀的字符串。如果有多个字符串与 wordsQuery[i] 有相同的最长公共后缀,则返回在 wordsContainer 中最早出现的那个。最后,返回一个整数数组 ans,其中 ans[i] 表示与 wordsQuery[i] 有最长公共后缀的字符串在 wordsContainer 中的下标。
福大大架构师每日一题
2024/10/29
900
2024-10-26:最长公共后缀查询。用go语言,给定两个字符串数组 wordsContainer 和 wordsQuery,
2025-04-22:形成目标字符串需要的最少字符串数Ⅰ。用go语言,给定一个字符串数组 words 和一个目标字符串 targ
2025-04-22:形成目标字符串需要的最少字符串数Ⅰ。用go语言,给定一个字符串数组 words 和一个目标字符串 target。
福大大架构师每日一题
2025/04/22
770
2025-04-22:形成目标字符串需要的最少字符串数Ⅰ。用go语言,给定一个字符串数组 words 和一个目标字符串 targ
2024-08-03:用go语言,给定一个从 0 开始的字符串数组 `words`, 我们定义一个名为 `isPrefixAnd
我们定义一个名为 isPrefixAndSuffix 的布尔函数,该函数接受两个字符串参数 str1 和 str2。
福大大架构师每日一题
2024/08/16
1290
2024-08-03:用go语言,给定一个从 0 开始的字符串数组 `words`, 我们定义一个名为 `isPrefixAnd
【LeetCode】括号问题——2116. 判断一个括号字符串是否有效(解法二)
相关标签:栈、贪心、字符串 题目难度:中等 题目描述 一个括号字符串是只由 '(' 和 ')' 组成的 非空 字符串。 如果一个字符串满足下面 任意 一个条件,那么它就是有效的:
蒙奇D索隆
2025/03/25
820
【LeetCode】括号问题——2116. 判断一个括号字符串是否有效(解法二)
2025-05-15:统计能获胜的出招序列数。用go语言,给定一个目标字符串 target,Alice 使用一个特殊键盘输入该字
2025-05-15:统计能获胜的出招序列数。用go语言,给定一个目标字符串 target,Alice 使用一个特殊键盘输入该字符串。这个键盘有两个按键:
福大大架构师每日一题
2025/05/15
290
2025-05-15:统计能获胜的出招序列数。用go语言,给定一个目标字符串 target,Alice 使用一个特殊键盘输入该字
2025-04-30:字典序最小的合法序列。用go语言,给定两个字符串 word1 和 word2。 定义“几乎相等”:如果字符
2025-04-30:字典序最小的合法序列。用go语言,给定两个字符串 word1 和 word2。
福大大架构师每日一题
2025/04/30
310
2025-04-30:字典序最小的合法序列。用go语言,给定两个字符串 word1 和 word2。 定义“几乎相等”:如果字符
2025-05-01:第一个几乎相等子字符串的下标。用go语言,给定两个字符串 s 和 pattern。 如果字符串 x 修改
2025-05-01:第一个几乎相等子字符串的下标。用go语言,给定两个字符串 s 和 pattern。
福大大架构师每日一题
2025/05/01
320
2025-05-01:第一个几乎相等子字符串的下标。用go语言,给定两个字符串 s 和 pattern。 如果字符串 x 修改
2021-05-26:给定一个char[][] matrix,也就是char类型的二维数组,再给定一个字符串word,可以从任何
2021-05-26:给定一个char[][] matrix,也就是char类型的二维数组,再给定一个字符串word,可以从任何一个某个位置出发,可以走上下左右,能不能找到word?char[][] m = {{ 'a', 'b', 'z' }, { 'c', 'd', 'o' }, { 'f', 'e', 'o' }}。设定1:可以走重复路的情况下,返回能不能找到。比如,word = "zoooz",是可以找到的,z -> o -> o -> o -> z,因为允许走一条路径中已经走过的字符。设定2:不可以走重复路的情况下,返回能不能找到。比如,word = "zoooz",是不可以找到的,因为允许走一条路径中已经走过的字符不能重复走。
福大大架构师每日一题
2021/08/05
5660
2025-05-30:统计平衡排列的数目。用go语言,给定一个数字字符串 num,如果该字符串中所有位于奇数索引位置的数字之和与
2025-05-30:统计平衡排列的数目。用go语言,给定一个数字字符串 num,如果该字符串中所有位于奇数索引位置的数字之和与所有位于偶数索引位置的数字之和相等,则称这个字符串是“平衡”的。
福大大架构师每日一题
2025/06/06
580
2025-05-30:统计平衡排列的数目。用go语言,给定一个数字字符串 num,如果该字符串中所有位于奇数索引位置的数字之和与
2025-05-10:从原字符串里进行删除操作的最多次数。用go语言,给定一个长度为 n 的字符串 source,以及一个字符串
2025-05-10:从原字符串里进行删除操作的最多次数。用go语言,给定一个长度为 n 的字符串 source,以及一个字符串 pattern,且 pattern 是 source 的子序列。另外,还有一个有序数组 targetIndices,数组中的元素是 [0, n-1] 范围内且互不相同的整数。
福大大架构师每日一题
2025/05/10
370
2025-05-10:从原字符串里进行删除操作的最多次数。用go语言,给定一个长度为 n 的字符串 source,以及一个字符串
2021-07-02:正则表达式匹配。给定一个字符串s和一个匹配串p。“.“匹配单个字符
2021-07-02:正则表达式匹配。给定一个字符串s和一个匹配串p。"."匹配单个字符。""匹配左边元素的多个字符。判断p是否匹配s。比如s="ab",p="a.",返回true。比如s="ab",p="a",返回false。比如s="aaa",p="a",返回true。比如s="moonfdd",p="kmoonfdd",返回true,因为"*"表示零个或者多个,这里'k'表示0个。
福大大架构师每日一题
2021/07/02
4520
2021-07-02:正则表达式匹配。给定一个字符串s和一个匹配串p。“.“匹配单个字符
2025-05-02:找出第 K 个字符Ⅰ。用go语言,Alice 和 Bob 玩一个游戏。起初,Alice 有一个字符串,内容
2025-05-02:找出第 K 个字符Ⅰ。用go语言,Alice 和 Bob 玩一个游戏。起初,Alice 有一个字符串,内容是 "a"。
福大大架构师每日一题
2025/05/02
460
2025-05-02:找出第 K 个字符Ⅰ。用go语言,Alice 和 Bob 玩一个游戏。起初,Alice 有一个字符串,内容
2024-05-11:用go语言,给定一个从零开始索引的字符串 s, 以及两个字符串 a 和 b,还有一个整数 k。 定义美丽下
输入:s = "isawsquirrelnearmysquirrelhouseohmy", a = "my", b = "squirrel", k = 15。
福大大架构师每日一题
2024/05/17
1420
2024-05-11:用go语言,给定一个从零开始索引的字符串 s, 以及两个字符串 a 和 b,还有一个整数 k。 定义美丽下
2025-04-18:求出数组中最大序列值。用go语言,给定一个整数数组 nums 和一个正整数 k。 定义一个长度为 2*k
2025-04-18:求出数组中最大序列值。用go语言,给定一个整数数组 nums 和一个正整数 k。 定义一个长度为 2*k 的子序列 seq 的值为:
福大大架构师每日一题
2025/04/18
480
2025-04-18:求出数组中最大序列值。用go语言,给定一个整数数组 nums 和一个正整数 k。 定义一个长度为 2*k
2025-05-22:找到初始输入字符串Ⅱ。用go语言,Alice 在键盘上输入一个字符串,但由于输入时可能按键时间过长,导致某
2025-05-22:找到初始输入字符串Ⅱ。用go语言,Alice 在键盘上输入一个字符串,但由于输入时可能按键时间过长,导致某些字符被重复输入多次。
福大大架构师每日一题
2025/05/22
380
2025-05-22:找到初始输入字符串Ⅱ。用go语言,Alice 在键盘上输入一个字符串,但由于输入时可能按键时间过长,导致某
2025-04-27:统计重新排列后包含另一个字符串的子字符串数目Ⅱ。用go语言,给定两个字符串 word1 和 word2,
2025-04-27:统计重新排列后包含另一个字符串的子字符串数目Ⅱ。用go语言,给定两个字符串 word1 和 word2,
福大大架构师每日一题
2025/04/27
560
2025-04-27:统计重新排列后包含另一个字符串的子字符串数目Ⅱ。用go语言,给定两个字符串 word1 和 word2,
2024-10-08:用go语言,给定一个字符串 word 和一个整数 k,判断是否可以通过删除最少数量的字符使得该字符串成为
2024-10-08:用go语言,给定一个字符串 word 和一个整数 k,判断是否可以通过删除最少数量的字符使得该字符串成为 k 特殊字符串。
福大大架构师每日一题
2024/10/10
1050
2024-10-08:用go语言,给定一个字符串 word 和一个整数 k,判断是否可以通过删除最少数量的字符使得该字符串成为
用javascript分类刷leetcode20.字符串(图文视频讲解)2
方法1.截取字符串,循环字符串,遇到#就截掉最后一个字符,循环完毕之后,最后比较两个去除掉#退格之后的字符串是否相等,时间复杂度O(m+n),m、n是两个字符串的长度。空间复杂度O(1)
hellocoder2028
2023/01/04
7910
2024-07-10:用go语言,给定一个字符串数组words,其中包含一些字符串。可以通过任意次数的操作来交换字符串中的字符。
2024-07-10:用go语言,给定一个字符串数组words,其中包含一些字符串。可以通过任意次数的操作来交换字符串中的字符。每次操作可选两个位置上的字符进行交换。问经过操作后,数组中最多可以形成多少个回文串。
福大大架构师每日一题
2024/08/16
1700
2024-07-10:用go语言,给定一个字符串数组words,其中包含一些字符串。可以通过任意次数的操作来交换字符串中的字符。
推荐阅读
搞定大厂算法面试之leetcode精讲20.字符串
7220
2024-10-26:最长公共后缀查询。用go语言,给定两个字符串数组 wordsContainer 和 wordsQuery,
900
2025-04-22:形成目标字符串需要的最少字符串数Ⅰ。用go语言,给定一个字符串数组 words 和一个目标字符串 targ
770
2024-08-03:用go语言,给定一个从 0 开始的字符串数组 `words`, 我们定义一个名为 `isPrefixAnd
1290
【LeetCode】括号问题——2116. 判断一个括号字符串是否有效(解法二)
820
2025-05-15:统计能获胜的出招序列数。用go语言,给定一个目标字符串 target,Alice 使用一个特殊键盘输入该字
290
2025-04-30:字典序最小的合法序列。用go语言,给定两个字符串 word1 和 word2。 定义“几乎相等”:如果字符
310
2025-05-01:第一个几乎相等子字符串的下标。用go语言,给定两个字符串 s 和 pattern。 如果字符串 x 修改
320
2021-05-26:给定一个char[][] matrix,也就是char类型的二维数组,再给定一个字符串word,可以从任何
5660
2025-05-30:统计平衡排列的数目。用go语言,给定一个数字字符串 num,如果该字符串中所有位于奇数索引位置的数字之和与
580
2025-05-10:从原字符串里进行删除操作的最多次数。用go语言,给定一个长度为 n 的字符串 source,以及一个字符串
370
2021-07-02:正则表达式匹配。给定一个字符串s和一个匹配串p。“.“匹配单个字符
4520
2025-05-02:找出第 K 个字符Ⅰ。用go语言,Alice 和 Bob 玩一个游戏。起初,Alice 有一个字符串,内容
460
2024-05-11:用go语言,给定一个从零开始索引的字符串 s, 以及两个字符串 a 和 b,还有一个整数 k。 定义美丽下
1420
2025-04-18:求出数组中最大序列值。用go语言,给定一个整数数组 nums 和一个正整数 k。 定义一个长度为 2*k
480
2025-05-22:找到初始输入字符串Ⅱ。用go语言,Alice 在键盘上输入一个字符串,但由于输入时可能按键时间过长,导致某
380
2025-04-27:统计重新排列后包含另一个字符串的子字符串数目Ⅱ。用go语言,给定两个字符串 word1 和 word2,
560
2024-10-08:用go语言,给定一个字符串 word 和一个整数 k,判断是否可以通过删除最少数量的字符使得该字符串成为
1050
用javascript分类刷leetcode20.字符串(图文视频讲解)2
7910
2024-07-10:用go语言,给定一个字符串数组words,其中包含一些字符串。可以通过任意次数的操作来交换字符串中的字符。
1700
相关推荐
搞定大厂算法面试之leetcode精讲20.字符串
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验