Leetcode打卡:形成目标字符串需要的最少字符串数II

执行结果:通过

题目:3292 形成目标字符串需要的最少字符串数II

给你一个字符串数组 words 和一个字符串 target

如果字符串 xwords任意字符串的

前缀

,则认为 x 是一个 有效 字符串。

现计划通过 连接 有效字符串形成 target ,请你计算并返回需要连接的 最少 字符串数量。如果无法通过这种方式形成 target,则返回 -1

示例 1:

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

输出: 3

解释:

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

  • words[1] 的长度为 2 的前缀,即 "aa"
  • words[2] 的长度为 3 的前缀,即 "bcd"
  • words[0] 的长度为 3 的前缀,即 "abc"

示例 2:

输入: words = ["abababab","ab"], target = "ababaababa"

输出: 2

解释:

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

  • words[0] 的长度为 5 的前缀,即 "ababa"
  • words[0] 的长度为 5 的前缀,即 "ababa"

示例 3:

输入: words = ["abcdef"], target = "xyz"

输出: -1

提示:

  • 1 <= words.length <= 100
  • 1 <= words[i].length <= 5 * 104
  • 输入确保 sum(words[i].length) <= 105.
  • words[i] 只包含小写英文字母。
  • 1 <= target.length <= 5 * 104
  • target 只包含小写英文字母。

代码以及解题思路

代码

复制代码
class Solution:
    def minValidStrings(self, words: List[str], target: str) -> int:
        n = reduce(lambda a, b: a + len(b), words, 1)
        ac = AC(n)
        for i, word in enumerate(words):
            ac.insert(word, 1)
        ac.build()
        ans = ac.search(target)
        return ans
class AC:

    def __init__(self, N: int):
        self.tot = 0
        self.tr = [[0] * 26 for _ in range(N)]
        self.e = [0] * N 
        self.cost = [1] * N
        self.len = [0] * N
        self.fail = [0] * N
        self.last = [0] * N
        

    def insert(self, word: str, cost: int) -> None:
        u = 0
        for i, ch in enumerate(word):
            ch = ord(ch) - ord("a")
            if self.tr[u][ch] == 0:
                self.tot += 1
                self.tr[u][ch] = self.tot
            u = self.tr[u][ch]
        
   
            self.len[u] = i + 1
            self.e[u] += 1
    
    def build(self) -> None:

        dq = deque()
        for i in range(26):
            if self.tr[0][i] != 0:
                dq.append(self.tr[0][i])


        while dq:
            u = dq.popleft()
            for i in range(26):
                if self.tr[u][i] != 0:
                    self.fail[self.tr[u][i]] = self.tr[self.fail[u]][i]
                    self.last[self.tr[u][i]] = self.fail[self.tr[u][i]] if self.len[self.fail[self.tr[u][i]]] else self.last[self.fail[self.tr[u][i]]]
                    dq.append(self.tr[u][i])
                else:
                    self.tr[u][i] = self.tr[self.fail[u]][i]
        


    def search(self, word: str) -> int:
        n = len(word)
        dp = [0] * (n+1)
        u = 0
        for i in range(1, n+1):
            ch = ord(word[i-1]) - ord("a")
            u = self.tr[u][ch]
            if u == 0:
                return -1
            dp[i] = dp[i - self.len[u]] + 1
        return dp[n]

解题思路:

  1. 初始化 AC 自动机
    • AC 自动机是一种用于多模式字符串匹配的数据结构,可以看作是一个Trie(前缀树)与KMP(Knuth-Morris-Pratt)算法的结合。
    • 初始化时,需要构建一个Trie树,并添加失败指针(fail指针),使得在匹配失败时可以跳转到另一个状态继续匹配。
  2. 构建 AC 自动机
    • 将所有单词插入到Trie树中,并记录每个节点的信息,如节点对应的字符串长度、是否是某个单词的结尾等。
    • 使用广度优先搜索(BFS)构建失败指针,使得每个节点在匹配失败时可以跳转到另一个节点继续匹配。
  3. 动态规划求解最小有效字符串数量
    • 使用动态规划数组 dp,其中 dp[i] 表示形成 target 的前 i 个字符所需的最小有效字符串数量。
    • 遍历 target 的每个字符,利用AC自动机在Trie树中查找当前字符可能匹配的最长前缀。
    • 更新 dp[i]dp[i - len(匹配的前缀)] + 1,表示通过添加一个有效字符串(包含当前匹配的前缀)来形成 target 的前 i 个字符。
    • 如果在某个位置无法匹配任何前缀(即AC自动机的当前状态为0),则无法形成 target,返回 -1。
  4. 返回结果
    • 遍历完成后,dp[n]ntarget 的长度)即为形成整个 target 所需的最小有效字符串数量。

代码细节

  • reduce(lambda a, b: a + len(b), words, 1):计算所有单词的总长度,用于初始化AC自动机的大小。
  • AC 类:实现了AC自动机的构建和搜索功能。
    • insert 方法:将单词插入Trie树。
    • build 方法:构建失败指针。
    • search 方法:使用动态规划搜索形成 target 的最小有效字符串数量。

注意事项

相关推荐
IT猿手20 分钟前
基于强化学习 Q-learning 算法求解城市场景下无人机三维路径规划研究,提供完整MATLAB代码
神经网络·算法·matlab·人机交互·无人机·强化学习·无人机三维路径规划
熊大如如3 小时前
Java 反射
java·开发语言
猿来入此小猿3 小时前
基于SSM实现的健身房系统功能实现十六
java·毕业设计·ssm·毕业源码·免费学习·猿来入此·健身平台
万能程序员-传康Kk4 小时前
旅游推荐数据分析可视化系统算法
算法·数据分析·旅游
PXM的算法星球4 小时前
【并发编程基石】CAS无锁算法详解:原理、实现与应用场景
算法
ll7788114 小时前
C++学习之路,从0到精通的征途:继承
开发语言·数据结构·c++·学习·算法
烨然若神人~4 小时前
算法第十七天|654. 最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树
算法
爱coding的橙子4 小时前
每日算法刷题Day2 5.10:leetcode数组1道题3种解法,用时40min
算法·leetcode
goTsHgo4 小时前
Spring Boot 自动装配原理详解
java·spring boot
阳洞洞4 小时前
leetcode 18. 四数之和
leetcode·双指针