加粗样式
用Python实现的动态规划求解字符串分解函数如下:
其中a是待分解字符串,b是可分解为的子字符串集合。
def count_composition_ways_optimized(a: str, b: set) -> int:
"""
优化版本:限制子串最大长度,提高效率
"""
n = len(a)
if n == 0:
return 1
# 计算集合中字符串的最大长度
max_len = max(len(word) for word in b) if b else 0
dp = [0] * (n + 1)
dp[0] = 1
for i in range(1, n + 1):
# 只检查可能的子串长度,避免不必要的检查
for length in range(1, min(i, max_len) + 1):
start = i - length
if a[start:i] in b:
dp[i] += dp[start]
#print(i, length,start,dp)
print(i, dp)
return dp[n]
a,b='bike', ['bi', 'l','ike']
print(count_composition_ways_optimized(a, b))
python dppy.txt"
#a=bill
1 [1, 0, 0, 0, 0]
2 [1, 0, 1, 0, 0]
3 [1, 0, 1, 1, 0]
4 [1, 0, 1, 1, 1]
1
#a=bike
1 [1, 0, 0, 0, 0]
2 [1, 0, 1, 0, 0]
3 [1, 0, 1, 0, 0]
4 [1, 0, 1, 0, 0]
0
改写有如下几个难点:
1.python有两个循环,在内循环会多次修改dp[i]的值,而且要读取dp[start]的值,而CTE查询要在下一轮才能读到上次改后的值,通过保持完整的dp解决
2.python的字符串和数组索引都是从0开始,DuckDB的字符串和列表都是从1开始,用dp[0]访问返回NULL,与其他值运算后会把运算结果也变成NULL,需要单独判断0下标,然后用字面值代替。
3.平常的CTE终止条件都是<某个值,迭代次数不够,dp的值还未更改,需要改成<=才能取到更改后的dp。
最后形成的语句如下,
with recursive test as (select 'bill' a, ['bi', 'l','ike']b) --(select 'bike' a, ['bi', 'l','ike']b)--
, n as(select length(a) n from test)
, maxlen as(select array_aggr([len(word) for word in b], 'max') maxlen from test)
, dp as(select repeat([0], n)dp from n)
, t as(
select True l,a,a a1,b, 1 i, dp from dp,test
union all
(with recursive d as(
select l lo,a,a1,b,i, 1 le, dp d from t
union all
select a[i-le+1:i] in b and i-(le) =0,a,a[i-le+1:i],b,i, le+1, d[1:i-1]||
[case when a[i-le+1:i] in b then d[i]+case when i-(le) >0 then d[i-(le)] else 1 end else d[i] end]
||d[i+1:] from n, maxlen,d where le<=i --least(i, maxlen)
)
select lo,a,a1,b,d.i+1 lv, d from d where d.i<=4 and le=d.i+1
)
)
select a,b,dp[4]from t where i=5;
执行结果
.read dp1.txt
┌─────────┬──────────────┬───────┐
│ a │ b │ dp[4] │
│ varchar │ varchar[] │ int32 │
├─────────┼──────────────┼───────┤
│ bike │ [bi, l, ike] │ 0 │
└─────────┴──────────────┴───────┘
.read dp1.txt
┌─────────┬──────────────┬───────┐
│ a │ b │ dp[4] │
│ varchar │ varchar[] │ int32 │
├─────────┼──────────────┼───────┤
│ bill │ [bi, l, ike] │ 1 │
└─────────┴──────────────┴───────┘
可以把上述查询最后一条语句修改为select i,a,b,a1,dp from t查看中间结果,可见,除了dp[0]不存在,其他和python的结果一致。
┌───────┬─────────┬──────────────┬─────────┬──────────────┐
│ i │ a │ b │ a1 │ dp │
│ int32 │ varchar │ varchar[] │ varchar │ int32[] │
├───────┼─────────┼──────────────┼─────────┼──────────────┤
│ 1 │ bill │ [bi, l, ike] │ bill │ [0, 0, 0, 0] │
│ 2 │ bill │ [bi, l, ike] │ b │ [0, 0, 0, 0] │
│ 3 │ bill │ [bi, l, ike] │ bi │ [0, 1, 0, 0] │
│ 4 │ bill │ [bi, l, ike] │ bil │ [0, 1, 1, 0] │
│ 5 │ bill │ [bi, l, ike] │ bill │ [0, 1, 1, 1] │
└───────┴─────────┴──────────────┴─────────┴──────────────┘
┌───────┬─────────┬──────────────┬─────────┬──────────────┐
│ i │ a │ b │ a1 │ dp │
│ int32 │ varchar │ varchar[] │ varchar │ int32[] │
├───────┼─────────┼──────────────┼─────────┼──────────────┤
│ 1 │ bike │ [bi, l, ike] │ bike │ [0, 0, 0, 0] │
│ 2 │ bike │ [bi, l, ike] │ b │ [0, 0, 0, 0] │
│ 3 │ bike │ [bi, l, ike] │ bi │ [0, 1, 0, 0] │
│ 4 │ bike │ [bi, l, ike] │ bik │ [0, 1, 0, 0] │
│ 5 │ bike │ [bi, l, ike] │ bike │ [0, 1, 0, 0] │
└───────┴─────────┴──────────────┴─────────┴──────────────┘
这个实现还很初步,还不能对多行数据分解,需要进一步研究。

1542

被折叠的 条评论
为什么被折叠?



