leetcode 第 377 场比赛第四题

作者: | 更新日期:

继续优化,降低常数。

本文首发于公众号:天空的代码世界,微信号:tiankonguse

零、背景

上篇文章《leetcode 第 377 场算法比赛》提到,最后一题我使用O(1000^2)的复杂度超时了。

于是我参考了下其他人的代码,继续优化了下算法,分享下优化思路。

比赛代码:
https://github.com/tiankonguse/leetcode-solutions/tree/master/contest

一、题意

题意:给一个字符串映射到另外一个字符串的代价,问原始字符串是否可以替换为目标字符串,求最小代价。
规则:原始字符串到目标字符串的映射过程中,映射的子串之间不能有交集(相等除外)。

基本思路:

第一步:对映射的字符串进行hash处理,转化为数字之间的映射,并求全源最短路。
复杂度:O(200^3)

第二步:对原始字符串和目标字符串的所有子串进行预处理,求出对应的hash值。
复杂度:O(1000^2)

第三步:动态规划,枚举判断原始字符串后缀是否可以替换到目标字符串后缀。
方程:dp[i] = min(dp[j-1] + cost[fromHash][toHash] )
复杂度:O(1000^2)

二、全源最短路优化

全源最短路的复杂度最高。

由于点数最多200,边数最多只有 100 个,换其他最短路算法可以更优。

例如使用 SPFA+堆 单源最短路优化,复杂度只与边的个数有关。
复杂度降为:O(200^2)

三、hash 优化

我们计算了任意子串之间的 hash 值,空间复杂度和时间复杂度都是O(1000^2)

其实可以只计算前缀的 hash,子串的 hash 可以通过两个前缀的差值来计算。

差值计算公式

f(l,r) = (f(0,r) - f(0,l-1) * base^(r-l+1)) % mod

前缀和base的幂都可以预处理,复杂度:O(1000)
计算子串hash的复杂度:O(1)

四、动态规划优化

默认动态规划是枚举所有长度,复杂度是 O(1000^2)

实际上,替换的点只有 100 个,说明可以替换的字符串长度最多最有 100 个。

故可以只枚举字符串长度集合。

复杂度:O(1000*100)

五、最后

优化后,各步骤的优化效果如下

第一步:求全源最短路 优化前:O(200^3) 优化后:O(200^2)

第二步:计算hash值
优化前:O(1000^2)
优化后:O(1000)

第三步:动态规划
优化前:O(1000^2)
优化后:O(1000*100)

最终优化完,使用 176ms 通过了这道题。
优化前耗时至少 176ms,稍微加点常数,耗时就超过 2 秒了。

《完》

-EOF-

本文公众号:天空的代码世界
个人微信号:tiankonguse
公众号ID:tiankonguse-code

本文首发于公众号:天空的代码世界,微信号:tiankonguse
如果你想留言,可以在微信里面关注公众号进行留言。

关注公众号,接收最新消息

tiankonguse +
穿越