B - Combine String (思维,不用DP直接for干就完事了)

这篇博客介绍了一个字符串组合问题的解决方案,给定三个字符串a、b和c,判断c是否由a和b的子序列组合而成。通过分析相对位置关系,提出了一种匹配策略,并提供了AC代码。文章强调了边界条件处理的重要性,并通过举例和证明说明了算法的正确性。
摘要由CSDN通过智能技术生成

目录

题目如下:

 中文翻译:

思路

我们可以发现什么:

AC代码如下(带简单的注释)

代码 单独拉出 边界特判(再次强调一下)


题目如下:

Given three strings a, b and c, your mission is to check whether c is the combine string of aaa and bbb.
A string c is said to be the combine string of a and b if and only if c can be broken into two subsequences, when you read them as a string, one equals to aaa, and the other equals to bbb.
For example, ``adebcf'' is a combine string of ``abc'' and ``def''.

Input

Input file contains several test cases (no more than 20). Process to the end of file.
Each test case contains three strings a, b and c (the length of each string is between 1 and 2000).

Output

For each test case, print ``Yes'', if c is a combine string of a and b, otherwise print ``No''.

Sample

InputOutput
 
abc def adebcf abc def abecdf 
 
Yes No 

 中文翻译:

给定三个字符串a、b和c,你的任务是检查c是否是a和b的组合字符串。 字符串c被称为a和b的组合字符串,当且仅当c可以被分解为两个子序列时,当你将它们作为字符串读取时,一个等于a,另一个等于b。 例如,“adebcf”是“abc”和“def”的组合字符串。

输入文件包含几个测试用例(不超过20个)。处理到文件末尾。 每个测试用例包含三个字符串a、b和c(每个字符串的长度在1到2000之间)。

对于每个测试用例,如果c是a和b的组合字符串,则打印“是”,否则打印“否”。

思路

我们可以把a串所有元素拆开,然后按相对位置关系固定起来,再把b串所有元素拆开按相对位置关系插入进去

如果不好理解,我直接上图帮助大家理解这个思路 (:  Q^Q

读者大大们可以多弄几个,理解一下这个思想!!!

我们可以发现什么:

如果可以满足题意(c串切成两个子串,两个子串正好分别等于a串,b串)

从左到右依次匹配a,b串,一定可以匹配成功的

证明:

我们可以结合上面,按相对位置关系固定a串元素,将b串元素按相对位置关系插入到里面 这个思想去证明!

简单来说(用人话来说):如果可以满足题意,c串一定是可以按照上面的方式构造出来,我们按照上面方式依次匹配,如果可以匹配完成则是Yes,否则是No。

似乎上面说的是很好,但是聪明的你会发现

如果是:

a:ab

b:ba

c:abab

a串先匹配一个后变成下面情况:

a:b

b:ba

c:bab

不难发现,a串与b串都可以匹配c串的b

那怎么办?

如果存在歧义(两串都可以匹配到),我们就接着往下看(看之后的匹配状态)

b串的a可以匹配c串的a并且b串无法匹配成功,那我们就解决了上面的歧义,我们可以把c串的b给b串

这样做一定是正确的嘛?

下面是简单的证明:

因为我们要保证a与b串自身的相对位置关系,所以我们解决 歧义 要在 相对位置关系的保持不变的前提下进行解决,这恰恰就是这个题的核心 & 操纵正确性的证明

举个例子:

如果c串的b给a串,a已完全匹配成功,c串剩下ab,b串剩下ba,发现b串已经无法匹配c串,但这个样例明明是Yes啊(可以完全匹配成功),这是因为我们已经破环了a与b串自身的相对位置关系了。

ps:可能讲的有点模糊,自身水平有限,希望您可以多看几遍思想,按这个思想多模拟几个样例,我想聪明的读者应该可以粗略的理解这个思想的可行性与正确性!

(:(:(:

还有一点需要特别注意欧!!!

一定要特别注意一下边界问题

类似:

a:aaaa

b:aaaa

c:aaaaaaaa

因为一直存在歧义,如果都匹配到头还是存在歧义的话,那就随便让一个串匹配就好啦!

AC代码如下(带简单的注释)

#include <bits/stdc++.h>
#define buff                     \
    ios::sync_with_stdio(false); \
    cin.tie(0);                  \
    cout.tie(0)
using namespace std;
const int N = 2009;
char a[N], b[N], c[N], d[N];
int na, nb, nc;
bool flag;
int main()
{
    buff;
    while (cin >> a)
    {
        cin >> b;
        cin >> c;
        flag = 1;
        na = strlen(a);
        nb = strlen(b);
        nc = strlen(c);
        if (nc != (na + nb))
        {
            puts("No");
            continue;
        }
        int i = 0, j = 0;
        for (int k = 0; k < nc; k++)
        {
            if (a[i] == c[k] && b[j] != c[k])//a可以匹配上(无分歧)
                i++;
            else if (a[i] != c[k] && b[j] == c[k])//b可以匹配上(无分歧)
                j++;
            else if (a[i] != c[k] && b[j] != c[k])//a,b都匹配不上,匹配直接失败
            {
                flag = 0;
                break;
            }
            else//a,b都匹配上,出现分歧(不知道到底让谁匹配,开始进行讨论)
            {
                int x = i + 1, y = j + 1;
                int ok = 0;//无答案(匹配失败)
                int z = k + 1;
                while (1)
                {
                    //辅助作用
                    // //----------下面是边界特判
                    // if(z==nc)
                    // break;
                    // if (x == na && y == nb)//匹配到头还是有歧义,那就随便让一个串匹配成功
                    // {
                    //     ok = 1;
                    //     break;
                    // }
                    // else if (x == na && y != nb)//就剩b可以匹配
                    // {
                    //     ok = 2;
                    //     break;
                    // }
                    // else if (y == nb && x != na)//就剩a可以匹配
                    // {
                    //     ok = 1;
                    //     break;
                    // }
                    // //-----------上面是边界特判

                    if (a[x] == c[z] && b[y] != c[z])//a匹配成功&b匹配失败,歧义解决
                    {
                        ok = 1; // a匹配
                        break;
                    }
                    else if (a[x] != c[z] && b[y] == c[z])//b匹配成功&a匹配失败,歧义解决
                    {
                        ok = 2; // b匹配
                        break;
                    }
                    else if (a[x] != c[z] && b[y] != c[z])//没有匹配成功但c没有匹配完,匹配接着进行
                    {
                        z++;
                        continue;
                    }
                    else//还是存在歧义,再往后看,看是否可以解决这个歧义
                    {
                        x++, y++, z++;
                    }
                }
                if (ok == 0)//匹配失败
                {
                    flag = 0;
                    break;
                }
                else if (ok == 1)//a匹配
                {
                    i++;
                }
                else//b匹配
                {
                    j++;
                }
            }
        }
        if (flag)
            puts("Yes");
        else
            puts("No");
    }
}

代码 单独拉出 边界特判(再次强调一下)

if (a[x] == c[z] && b[y] != c[z]) // a匹配成功&b匹配失败,歧义解决
{
    ok = 1; // a匹配
    break;
}
else if (a[x] != c[z] && b[y] == c[z]) // b匹配成功&a匹配失败,歧义解决
{
    ok = 2; // b匹配
    break;
}
else if (a[x] != c[z] && b[y] != c[z]) //没有匹配成功但c没有匹配完,匹配接着进行
{
    z++;
    continue;
}
else //还是存在歧义,再往后看,看是否可以解决这个歧义
{
    x++, y++, z++;
}

 我们一路奋战,不是为了改变世界,而是为了不让世界改变我们。——《熔炉》

最后感谢您的阅读!!!

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Joanh_Lan

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

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

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

打赏作者

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

抵扣说明:

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

余额充值