算法导论 — 思考题15-9 字符串拆分

字符串拆分)某种字符串处理语言允许程序员将一个字符串拆分为两段。由于此操作需要复制字符串,因此要花费 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) (1im)处被拆分,那么拆分下来的两个子串分别为 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 &lt; j ≤ m 1 ≤ i &lt; j ≤ m 1i<jm。那么,这个子串实际上为 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..j1]。我们要对这个子串再行拆分,用 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 &lt; j ≤ m 1 ≤ i &lt; j ≤ m 1i<jm。为解决整个问题,需要对 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..j1]。假设从 L [ k ] L[k] L[k] ( i &lt; k &lt; j ) (i &lt; k &lt; 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 &lt; k &lt; j i &lt; k &lt; 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值