如何选择无重叠子串组合以获得字典对应最高数值和?
嘿,这个问题其实是动态规划(DP)的经典应用场景——正则确实搞不定这种带最优选择的重叠判断,我来给你捋捋解决方案:
核心思路
我们可以用动态规划数组记录到字符串每个位置为止能获得的最大总和,通过逐步遍历每个位置,判断是否选择以当前位置结尾的子串,从而得到全局最优解。
具体步骤
- 初始化DP数组:创建一个长度为
len(s)+1的数组dp,其中dp[i]表示字符串前i个字符(即s[0..i-1])能得到的最大总和。初始时dp[0] = 0(空字符串的总和为0),其余位置先默认继承前一个位置的最大值。 - 遍历每个位置:从
i=1到i=len(s)逐个遍历:- 首先,
dp[i]至少等于dp[i-1](也就是不选当前字符的情况,总和和前i-1个字符的最大值一致)。 - 然后,遍历字典里的所有子串,检查是否有子串刚好以当前位置的字符结尾:
- 假设子串长度为
k,如果i >= k且s[i-k:i]等于该子串,那么我们可以考虑选择这个子串,此时的总和为dp[i-k] + d[子串](前i-k个字符的最大总和加上当前子串的数值)。 - 把这个值和当前的
dp[i]比较,取较大的更新dp[i]。
- 假设子串长度为
- 首先,
- 获取结果:最终
dp[len(s)]就是我们要的最大总和。
代码示例(Python)
def max_substring_sum(s, substring_dict): str_length = len(s) # 初始化DP数组,dp[0]对应空字符串,总和为0 dp = [0] * (str_length + 1) # 遍历字符串的每个位置(对应前i个字符) for i in range(1, str_length + 1): # 默认不选当前字符,继承前一个位置的最大值 dp[i] = dp[i-1] # 检查所有子串是否能匹配到当前位置结尾 for substr, value in substring_dict.items(): substr_len = len(substr) # 确保当前位置足够容纳子串,且子串匹配 if i >= substr_len and s[i - substr_len:i] == substr: # 计算选这个子串的总和,更新dp[i]为较大值 if dp[i - substr_len] + value > dp[i]: dp[i] = dp[i - substr_len] + value return dp[str_length]
举个例子验证
比如:
- 字符串
s = "abcab" - 字典
d = {"ab":3, "bc":2, "cab":5}
按照代码计算:
dp[0] = 0dp[1] = dp[0] = 0(没有子串能匹配前1个字符)dp[2] = max(dp[1], dp[0]+3) = 3(匹配到"ab")dp[3] = max(dp[2], dp[1]+2) = 3(匹配到"bc"但总和2比3小)dp[4] = dp[3] = 3(没有匹配的子串)dp[5] = max(dp[4], dp[3]+3, dp[2]+5) = max(3, 6, 8) = 8(匹配到"ab"总和6,匹配到"cab"总和8,取最大)
最终结果是8,对应选择"ab"(前2个字符)和"cab"(第3-5个字符),两个子串无重叠,总和3+5=8,确实是最优解。
为什么正则不行?
正则的核心是模式匹配,它只能按照贪婪/非贪婪规则匹配符合模式的子串,但没法处理这种需要权衡不同子串的数值、选择无重叠组合以得到最大总和的问题——正则没有“计算最优值”的能力,所以放弃正则是完全正确的选择。
小优化建议
如果字典里的子串数量很多,可以先把子串按长度从长到短排序,这样在检查时能优先匹配更长的子串,减少一些重复判断(不过不影响最终结果,只是提升效率)。
内容的提问来源于stack exchange,提问作者wokadakow
相关产品推荐
相关产品推荐

