
一、题目
1、题目描述
原字符串由小写字母组成,可以按下述步骤编码:
任意将其 分割 为由若干 非空 子字符串组成的一个 序列。任意选择序列中的一些元素(也可能不选择),然后将这些元素替换为元素各自的长度(作为一个数字型的字符串)。
重新 顺次连接 序列,得到编码后的字符串。
例如,编码
"abcdefghijklmnop"的一种方法可以描述为:
将原字符串分割得到一个序列:["ab", "cdefghijklmn", "o", "p"]。
选出其中第二个和第三个元素并分别替换为它们自身的长度。序列变为["ab", "12", "1", "p"]。重新顺次连接序列中的元素,得到编码后的字符串:"ab121p"。
给你两个编码后的字符串
s1和s2,由小写英文字母和数字 1-9 组成。如果存在能够同时编码得到s1和s2原字符串,返回true;否则,返回false。
注意:生成的测试用例满足s1和s2中连续数字数不超过3。
样例输入:s1 = "internationalization", s2 = "i18n"
样例输出:true
2、基础框架
- C语言 版本给出的基础框架代码如下:
bool possiblyEquals(char * s1, char * s2){
}

3、原题链接
二、解题报告
1、思路分析
(
1
)
(1)
(1) 假设两个串
s
1
s_1
s1 和
s
2
s_2
s2,对于
s
1
[
0
:
i
]
s_1[0:i]
s1[0:i] 和
s
2
[
0
:
j
]
s_2[0:j]
s2[0:j] 展开以后,前面部分完全匹配,并且它们的长度差值是一个集合。如下图所示,红色部分就两个串展开成原串以后,得到的它们的差值,所以图中的差值的集合就是
{
1
,
−
1
}
\{ 1, -1\}
{1,−1}。

(
2
)
(2)
(2) 所以我们的状态是一个集合,也就是说
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 表示的是
s
1
[
0
:
i
]
s_1[0:i]
s1[0:i] 和
s
2
[
0
:
j
]
s_2[0:j]
s2[0:j] 展开成原串以后,前缀完全匹配的情况下,多余字符串的差值的集合。
(
3
)
(3)
(3)
d
p
[
0
]
[
0
]
dp[0][0]
dp[0][0] 表示的是两个空串匹配后有可能差值集合,它等于
{
0
}
\{0 \}
{0}。
(
4
)
(4)
(4) 对于任意
d
p
[
i
]
[
j
]
[
k
]
>
=
0
dp[i][j][k] >= 0
dp[i][j][k]>=0 的情况,如果
s
2
[
j
+
1
]
s_2[j+1]
s2[j+1]是数字的话,我们可以想办法把
s
2
[
j
+
1
:
.
.
.
]
s_2[j+1:...]
s2[j+1:...] 凑成数字想办法减少差距,如下图所示:

对应的伪代码如下:
if(dp[i][j][k] >= 0) {
int num = 0;
for(int x = j + 1; x < m; ++x) {
if( isDigit(s2[x]) ) {
num = num * 10 + s2[x] - '0';
dp[i][x].emplace( dp[i][j][k] - num );
}else {
break;
}
}
}
(
5
)
(5)
(5) 对于任意
d
p
[
i
]
[
j
]
[
k
]
<
=
0
dp[i][j][k] <= 0
dp[i][j][k]<=0 的情况,如果
s
1
[
i
+
1
]
s_1[i+1]
s1[i+1]是数字的话,我们可以想办法把
s
1
[
i
+
1
:
.
.
.
]
s_1[i+1:...]
s1[i+1:...] 凑成数字想办法减少差距,如下图所示:

对应的伪代码如下:
if(dp[i][j][k] <= 0) {
int num = 0;
for(int x = i + 1; x < n; ++x) {
if(isDigit(s1[x])) {
num = num * 10 + s1[x] - '0';
dp[x][j].emplace( dp[i][j][k] + num );
}else {
break;
}
}
}
(
6
)
(6)
(6) 在考虑剩下的三种特殊情况:
(
6.1
)
(6.1)
(6.1) 如果
d
p
[
i
]
[
j
]
[
k
]
=
0
dp[i][j][k] = 0
dp[i][j][k]=0,并且
s
1
[
i
+
1
]
=
=
s
2
[
j
+
1
]
s_1[i+1] == s_2[j+1]
s1[i+1]==s2[j+1],则
d
p
[
i
+
1
]
[
j
+
1
]
dp[i+1][j+1]
dp[i+1][j+1] 必然能够加入一个 0 的情况。
(
6.2
)
(6.2)
(6.2) 如果
d
p
[
i
]
[
j
]
[
k
]
>
0
dp[i][j][k] > 0
dp[i][j][k]>0,并且
s
2
[
j
+
1
]
s_2[j+1]
s2[j+1] 是字母,则可以减少一个差距,也就是
d
p
[
i
]
[
j
+
1
]
[
k
]
=
d
p
[
i
]
[
j
]
[
k
]
−
1
dp[i][j+1][k] = dp[i][j][k] - 1
dp[i][j+1][k]=dp[i][j][k]−1。
(
6.3
)
(6.3)
(6.3) 如果
d
p
[
i
]
[
j
]
[
k
]
<
0
dp[i][j][k] < 0
dp[i][j][k]<0,并且
s
1
[
i
+
1
]
s_1[i+1]
s1[i+1] 是字母,则可以减少一个差距,也就是
d
p
[
i
+
1
]
[
j
]
[
k
]
=
d
p
[
i
]
[
j
]
[
k
]
+
1
dp[i+1][j][k] = dp[i][j][k] + 1
dp[i+1][j][k]=dp[i][j][k]+1。
2、时间复杂度
最坏时间复杂度 O ( n 4 ) O(n^4) O(n4)。
3、代码详解
#define maxn 45
class Solution {
bool isDigit(char c) {
return c >= '1' && c <= '9';
}
public:
bool possiblyEquals(string s1, string s2) {
unordered_set<int> dp[maxn][maxn];
s1 = "#" + s1;
s2 = "#" + s2;
int i, j;
int n = s1.size();
int m = s2.size();
dp[0][0].emplace(0);
for(i = 0; i < n; ++i) {
for(j = 0; j < m; ++j) {
for(auto sub : dp[i][j]) {
if(sub >= 0) {
int num = 0;
for(int x = j + 1; x < m; ++x) {
if( isDigit(s2[x]) ) {
num = num * 10 + s2[x] - '0';
dp[i][x].emplace( sub - num );
}else {
break;
}
}
}
if(sub <= 0) {
int num = 0;
for(int x = i + 1; x < n; ++x) {
if(isDigit(s1[x])) {
num = num * 10 + s1[x] - '0';
dp[x][j].emplace( sub + num );
}else {
break;
}
}
}
if(sub == 0 && s1[i+1] == s2[j+1]) {
dp[i+1][j+1].emplace(0);
}
if(sub > 0 && !isDigit(s2[j+1])) {
dp[i][j+1].emplace(sub - 1);
}
if(sub < 0 && !isDigit(s1[i+1])) {
dp[i+1][j].emplace(sub + 1);
}
}
}
}
return dp[n-1][m-1].count(0);
}
};
三、本题小知识
时间浪费掉了,太不值得啦,不建议做这个题。
四、加群须知
相信看我文章的大多数都是「 大学生 」,能上大学的都是「 精英 」,那么我们自然要「 精益求精 」,如果你还是「 大一 」,那么太好了,你拥有大把时间,当然你可以选择「 刷剧 」,然而,「 学好算法 」,三年后的你自然「 不能同日而语 」。
那么这里,我整理了「 几十个基础算法 」 的分类,点击开启:
如果链接被屏蔽,或者有权限问题,可以私聊作者解决。

大致题集一览:















为了让这件事情变得有趣,以及「 照顾初学者 」,目前题目只开放最简单的算法 「 枚举系列 」 (包括:线性枚举、双指针、前缀和、二分枚举、三分枚举),当有 一半成员刷完 「 枚举系列 」 的所有题以后,会开放下个章节,等这套题全部刷完,你还在群里,那么你就会成为「 夜深人静写算法 」专家团 的一员。
不要小看这个专家团,三年之后,你将会是别人 望尘莫及 的存在。如果要加入,可以联系我,考虑到大家都是学生, 没有「 主要经济来源 」,在你成为神的路上,「 不会索取任何 」。
🔥联系作者,或者扫作者主页二维码加群,加入刷题行列吧🔥
🔥让天下没有难学的算法🔥
C语言免费动漫教程,和我一起打卡! 🌞《光天化日学C语言》🌞
让你养成九天持续刷题的习惯 🔥《九日集训》🔥
入门级C语言真题汇总 🧡《C语言入门100例》🧡
组团学习,抱团生长 🌌《算法零基础100讲》🌌
几张动图学会一种数据结构 🌳《画解数据结构》🌳
竞赛选手金典图文教程 💜《夜深人静写算法》💜
本文探讨了一种字符串编码方法,通过将字符串拆分并替换部分子串为长度值,形成编码后的字符串。给定两个已编码字符串s1和s2,我们需要判断是否存在原始字符串使得两者都能编码得到。解题策略涉及动态规划,考虑字符匹配、数字处理以及可能的差值集合。时间复杂度为O(n^4)。文章还分享了相关算法知识和刷题资源,鼓励学习者提升算法能力。

1731

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



