(字符串拆分)某种字符串处理语言允许程序员将一个字符串拆分为两段。由于此操作需要复制字符串,因此要花费
n
n
n个时间单位来将一个
n
n
n个字符的字符串拆分为两段。假定一个程序员希望将一个字符串拆分为多段,拆分的顺序会影响所花费的时间。例如,假定这个程序员希望将一个20个字符的字符串在第2个、第8个及第10个字符后进行拆分(字符由左至右,从1开始升序编号)。如果她按由左至右的顺序进行拆分,则第一次拆分花费20位时间单位,第二次拆分花费18个时间单位(在第8个字符处拆分字符串3~20),而第三次拆分花费12个时间单位。共花费50个时间单位。但如果她按由右至左的顺序拆分,第一次拆分花费20个时间单位,第二次拆分花费10个时间单位,第三次拆分花费8个时间单位,共花费38个时间单位。还可以按其他顺序,比如,她可以首先在第8个字符处进行拆分(时间20),接着在左边一段第2个字符处进行拆分(时间8),最后在右边一段第10个字符处进行拆分(时间12),总时间为40。
设计算法,对给定的拆分位置,确定最小代价的拆分顺序。更形式化地,给定一个
n
n
n个字符的字符串
S
S
S和一个保存
m
m
m个拆分点的数组
L
[
1..
m
]
L[1..m]
L[1..m],计算拆分的最小代价,以及最优拆分顺序。
解
如果整个字符串
S
[
1..
n
]
S[1..n]
S[1..n]在第
L
[
i
]
L[i]
L[i]个字符
(
1
≤
i
≤
m
)
(1 ≤ i ≤ m)
(1≤i≤m)处被拆分,那么拆分下来的两个子串分别为
S
[
1..
L
[
i
]
]
S[1..L[i]]
S[1..L[i]]和
S
[
L
[
i
]
+
1..
n
]
S[L[i]+1..n]
S[L[i]+1..n]。假设一个子串是经由拆分得到的,它的左端是从原字符串的
L
[
i
]
L[i]
L[i]处拆分,它的右端是从原字符串的
L
[
j
]
L[j]
L[j]处拆分,其中
1
≤
i
<
j
≤
m
1 ≤ i < j ≤ m
1≤i<j≤m。那么,这个子串实际上为
S
[
L
[
i
]
+
1..
L
[
j
]
]
S[L[i]+1..L[j]]
S[L[i]+1..L[j]],并且这个子串的可选拆分点为
L
[
i
+
1..
j
−
1
]
L[i+1..j-1]
L[i+1..j−1]。我们要对这个子串再行拆分,用
s
p
[
i
,
j
]
sp[i, j]
sp[i,j]表示对这个子串首次拆分的拆分点在
L
L
L中的索引,并用
c
o
s
t
[
i
,
j
]
cost[i, j]
cost[i,j]表示对这个子串进行完全拆分所花费的时间。
上文提到,
i
i
i和
j
j
j的取值范围为
1
≤
i
<
j
≤
m
1 ≤ i < j ≤ m
1≤i<j≤m。为解决整个问题,需要对
i
i
i和
j
j
j的取值扩展一下。当
i
i
i取值为
0
0
0时,表示的子串为
S
[
1..
L
[
j
]
]
S[1..L[j]]
S[1..L[j]];当
j
j
j取值为
m
+
1
m+1
m+1时,表示的子串为
S
[
L
[
i
]
+
1..
n
]
S[L[i]+1..n]
S[L[i]+1..n]。显然,当
i
=
0
i = 0
i=0并且
j
=
m
+
1
j = m+1
j=m+1时,表示的子串实际上就是完整的字符串
S
[
1..
n
]
S[1..n]
S[1..n]。我们最终要求解的就是
i
=
0
i = 0
i=0并且
j
=
m
+
1
j = m+1
j=m+1的情况。相应地,我们要将拆分点数组
L
[
1..
m
]
L[1..m]
L[1..m]也扩展一下,扩展为
L
[
0..
m
+
1
]
L[0..m+1]
L[0..m+1],其中
L
[
0
]
=
0
L[0] = 0
L[0]=0,
L
[
m
+
1
]
=
n
L[m+1] = n
L[m+1]=n,其余数值保持不变。
我们现在求解一个子串的
c
o
s
t
[
i
,
j
]
cost[i, j]
cost[i,j]。这个子串的长度为
L
[
j
]
−
L
[
i
]
L[j]-L[i]
L[j]−L[i],可选拆分点为
L
[
i
+
1..
j
−
1
]
L[i+1..j-1]
L[i+1..j−1]。假设从
L
[
k
]
L[k]
L[k]处
(
i
<
k
<
j
)
(i < k < j)
(i<k<j)进行拆分,那么
c
o
s
t
[
i
,
j
]
=
L
[
j
]
−
L
[
i
]
+
c
o
s
t
[
i
,
k
]
+
c
o
s
t
[
k
,
j
]
cost[i, j] = L[j] - L[i] + cost[i, k] + cost[k, j]
cost[i,j]=L[j]−L[i]+cost[i,k]+cost[k,j]。我们遍历所有
k
k
k的取值
i
<
k
<
j
i < k < j
i<k<j,从中选取花费时间最小的。于是可以得到以下递归式。
该算法与矩阵链乘法问题相似,它的时间复杂度也为
O
(
m
3
)
O(m^3)
O(m3)。
本题相关的code链接。
https://github.com/yangtzhou2012/Introduction_to_Algorithms_3rd/tree/master/Chapter15/Problems/Problem_15-9
算法导论 — 思考题15-9 字符串拆分
最新推荐文章于 2023-02-01 20:13:13 发布