字符串字典序

本文探讨了字符串的字典序概念,并通过举例解析了在字符串拼接问题中,如何寻找字典序最小的拼接结果。错误的排序和动态规划方法被逐一分析,最终提出正确的解决方案——通过特定排序规则选择字符串并进行拼接。

字符串字典序

设字母集为 ∑ \sum (通常为小写字母), ∑ ∗ \sum^* 为表示包含所有有限长度的字符串的集合,该字符串是由字母表 ∑ \sum 中字符组成的,而字典序是定义在 ∑ ∗ \sum^* 上的一个偏序关系。

设两个字符串为 a a a b b b,则两个字符串的大小关系为:

  1. i = 1 i=1 i=1
  2. i ≤ min ⁡ { ∣ a ∣ , ∣ b ∣ } i \leq \min\{|a|,|b|\} imin{a,b}比较 a [ i ] a[i] a[i] b [ i ] b[i] b[i]之间的关系,若 a [ i ] < b [ i ] a[i] < b[i] a[i]<b[i],那么 a a a的字典序小于 b b b,若 a [ i ] > b [ i ] a[i] > b[i] a[i]>b[i],那么 a a a的字典序大于 b b b,若 a [ i ] = b [ i ] a[i] = b[i] a[i]=b[i]那么令 i + 1 i+1 i+1,继续比较。
  3. i > min ⁡ { ∣ a ∣ , ∣ b ∣ } i > \min\{|a|,|b|\} i>min{a,b},若 ∣ a ∣ < ∣ b ∣ |a| < |b| a<b,那么 a a a的字典序小于 b b b,若 ∣ a ∣ > ∣ b ∣ |a| > |b| a>b,那么 a a a的字典序大于 b b b,若 ∣ a ∣ = ∣ b ∣ |a| = |b| a=b那么两个字符串的字典序相同。

例题

字符串拼接问题

ABC 225F

给定 N N N个字符串,从中选取 J J J个字符串,拼接顺序自定,求字典序最小的拼接结果字符串。

首先列举 4 4 4个错误的做法:

第一种:

直接对 S i S_i Si按照字典序进行排序,然后取出前 J J J个字符串拼接在一起。

假设, J = 2 J = 2 J=2 A A A B B B的一个前缀,并且 ∣ A ∣ < ∣ B ∣ |A| < |B| A<B,这样按照第一种排序得到的下图最上面的字符串,而下面的字符串可能更优,考虑下图箭头处的比较位置,若在箭头处下面的字符串的字典序小于上面的字符串,那么下面的字符串才是最优解,因此第一种不可行。

例如:

2 2
b
ba

图例

第二种:

定义排序规则:若下标 i i i j j j满足 S i + S j < S j + S i S_i + S_j < S_j + S_i Si+Sj<Sj+Si,那么 S i S_i Si应该排列在 S j S_j Sj的前面,那么取出前 J J J个拼接即可。

考虑下述样例:

2 1
b
ba

由于第一种的错误性间接导致了第二种错误。

第三种:

定义排序规则:若下标 i i i j j j满足 S i + S j < S j + S i S_i + S_j < S_j + S_i Si+Sj<Sj+Si,那么 S i S_i Si应该排列在 S j S_j Sj的前面,那么取出前 J J J个拼接即可。

然后进行DP,设 d p [ i ] [ j ] dp[i][j] dp[i][j]是前 i i i个字符串里挑选 j j j个字符串的最小字典序结果串,有以下状态转移方程:

d p [ i ] [ j ] = min ⁡ ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − 1 ] + S i ) dp[i][j]=\min(dp[i−1][j],dp[i−1][j−1] + S_i) dp[i][j]=min(dp[i1][j],dp[i1][j1]+Si)

转移方程中 d p [ i − 1 ] [ j − 1 ] + S i dp[i−1][j−1] + S_i dp[i1][j1]+Si,并不一定是最小的以 S i S_i Si结尾的字典序,如图:

图例

B B B C C C的一个前缀,如果按照上述DP方程转移,得到的是下面的答案,但是如果考虑箭头比较的位置,那么上面的字符串的更优。

考虑下面的样例:

3 2
baa
ba
b
第四种:

定义排序规则:若下标 i i i j j j满足 S i + S j < S j + S i S_i + S_j < S_j + S_i Si+Sj<Sj+Si,那么 S i S_i Si应该排列在 S j S_j Sj的前面,那么取出前 J J J个拼接即可。

然后进行DP,设 d p [ i ] [ j ] dp[i][j] dp[i][j]是前 i i i个字符串里挑选 j j j个字符串的最小字典序结果串,有以下状态转移方程:

d p [ i ] [ j ] = min ⁡ ( d p [ i − 1 ] [ j ] , min ⁡ k < i d p [ k ] [ j − 1 ] + S i ) dp[i][j]=\min(dp[i−1][j],\min_{k < i}dp[k][j−1] + S_i) dp[i][j]=min(dp[i1][j],k<imindp[k][j1]+Si)

由第三种推广可知,由前 k k k个组成的最小字典序拼接 S i S_i Si不一定是最小的字典序,其本质原因出现在字符串前缀的问题上。

正确做法:

定义排序规则:若下标 i i i j j j满足 S i + S j < S j + S i S_i + S_j < S_j + S_i Si+Sj<Sj+Si,那么 S i S_i Si应该排列在 S j S_j Sj的前面,那么取出前 J J J个拼接即可。

可以保证,答案就是在排序好的序列中,挑选出 J J J个字符串,然后按照相对位置拼接,可以保证任意 J J J个字符串按照这样拼接的顺序是最小的。

然后考虑如何挑选出这 J J J个字符串。

考虑逆向DP,即:

d p [ i ] [ j ] = min ⁡ ( d p [ i + 1 ] [ j ] , S i + d p [ i + 1 ] [ j − 1 ] ) dp[i][j] = \min(dp[i+1][j],S_i + dp[i+1][j−1]) dp[i][j]=min(dp[i+1][j],Si+dp[i+1][j1])

为什么比上面的方程对,考虑下图:

前两个是从后往前DP, A A A即为 S i S_i Si,说明两个字典序的影响完全来自于后面的字符串。

后两个为从前往后DP,此时两个字典序的影响还受 A A A字符串的影响,不完全来自于前面的字符串,因此前面字符串的字典序最小不一定是最优拼接答案。

图例

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值