LeetCode 2060. 同源字符串检测

一、题目

1、题目描述

  原字符串由小写字母组成,可以按下述步骤编码:
任意将其 分割 为由若干 非空 子字符串组成的一个 序列。任意选择序列中的一些元素(也可能不选择),然后将这些元素替换为元素各自的长度(作为一个数字型的字符串)。
  重新 顺次连接 序列,得到编码后的字符串。

  例如,编码 "abcdefghijklmnop"的一种方法可以描述为:
将原字符串分割得到一个序列:["ab", "cdefghijklmn", "o", "p"]
选出其中第二个和第三个元素并分别替换为它们自身的长度。序列变为 ["ab", "12", "1", "p"]。重新顺次连接序列中的元素,得到编码后的字符串:"ab121p"

  给你两个编码后的字符串 s1s2,由小写英文字母和数字 1-9 组成。如果存在能够同时编码得到 s1s2原字符串,返回 true;否则,返回 false
  注意:生成的测试用例满足 s1s2中连续数字数不超过 3
  样例输入: s1 = "internationalization", s2 = "i18n"
  样例输出: true

2、基础框架

  • C语言 版本给出的基础框架代码如下:
bool possiblyEquals(char * s1, char * s2){

}

3、原题链接

LeetCode 2060. 同源字符串检测

二、解题报告

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讲》🌌

几张动图学会一种数据结构
🌳《画解数据结构》🌳

竞赛选手金典图文教程
💜《夜深人静写算法》💜
  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

英雄哪里出来

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值