You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求source子序列交错拼接为target的最小数量及方法正确性验证

思路正确性验证

你的贪心思路是完全正确的,证明可以用交换论证:

  • 假设存在一个最优解,其第一次选取的公共子序列长度为k,而你贪心选取的LCS长度为l,显然l >=k。
  • 你用LCS替换最优解的第一个子序列后,剩余待匹配的target长度比最优解剩余的更短,后续需要的步数不可能超过最优解的剩余步数,因此整体步数不会比最优解大,说明贪心策略可以得到最优解。

你的代码可以正确处理样例,逻辑没有问题。

更优的求解方案

你当前的实现时间复杂度较高,每次求LCS的时间是O(mn)(m是source长度,n是target长度),最坏情况下需要执行O(n)次,总复杂度是O(mn²),当n较大时会超时。
我们可以用O(n log n)的方法求解,思路基于Dilworth定理:

该问题等价于给target的每个字符分配一个source中的对应位置(同字符匹配),要求同一分组的位置严格递增,求最少分组数。根据Dilworth定理,最少分组数等于位置序列的最长严格递减子序列的长度。

具体步骤:

  1. 预处理source,记录每个字符出现的所有位置,用字典存储。如果target中存在source没有的字符,直接返回-1。
  2. 遍历target,构造位置序列:对于每个字符c,按顺序循环取source中c的位置,加入序列。
  3. 求该序列的最长严格递减子序列的长度,就是所求的最小个数。求最长递减子序列可以转化为求反序列的最长递增子序列,用二分优化实现O(n log n)的时间复杂度。

优化后的代码示例

import bisect
from collections import defaultdict

class Solution:
    def shortestWay(self, s: str, t: str) -> int:
        # 预处理每个字符在source中的位置
        pos = defaultdict(list)
        for idx, c in enumerate(s):
            pos[c].append(idx)
        # 检查target是否有source不存在的字符
        for c in t:
            if c not in pos:
                return -1
        # 构造位置序列
        ptr = defaultdict(int) # 每个字符当前取到第几个位置
        seq = []
        for c in t:
            lst = pos[c]
            seq.append(lst[ptr[c]])
            ptr[c] = (ptr[c] + 1) % len(lst)
        # 求最长严格递减子序列,转化为求反序列的最长严格递增子序列
        rev_seq = [-x for x in seq]
        dp = []
        for num in rev_seq:
            idx = bisect.bisect_left(dp, num)
            if idx == len(dp):
                dp.append(num)
            else:
                dp[idx] = num
        return len(dp)

用你给出的样例测试:

  • source = "adbsc",字符位置存储为{'a':[0],'d':[1],'b':[2],'s':[3],'c':[4]}
  • target = "addsbc",构造的序列是[0,1,1,3,2,4]
  • 反序列为[0,-1,-1,-3,-2,-4],最长递增子序列长度是2,和预期输出一致。

内容的提问来源于stack exchange,提问作者GooT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 21:36:03