牛客21805 字符串编码与解码(模拟+枚举)

本文介绍了一个字符串解码问题,给出两个长度相同的字符串a和b,其中b是a编码后的结果。文章提供了详细的解题思路,包括如何判断字符串是否可解码,以及在特定条件下如何推断未知字符的解码。

链接:https://ac.nowcoder.com/acm/problem/21805
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

给你两个长度相同的字符串a,b,现在已知b是a编码之后的结果
比如a = "CAT", b = "DOG", 那么D其实是C,O其实是A,G其实是T

现在给你一个字符串c,如果c能够被解码出来,输出c解码后的字符串,如果不能输出@

输入描述:

输入三行,每行一个字符串,长度在50以内

输出描述:

输出一个字符串

示例1

输入

复制

CAT
DOG
GOD

输出

复制

TAC

示例2

输入

复制

BANANA
METETE
TEMP

输出

复制

@

示例3

输入

复制

THEQUICKBROWNFOXJUMPSOVERTHELAZYHOG
UIFRVJDLCSPXOGPYKVNQTPWFSUIFMBAZIPH
DIDYOUNOTICESKIPPEDLETTER

输出

复制

CHCXNTMNSHBDRJHOODCKDSSDQ

备注:

子任务1:|a| <= 10
子任务2:|a| <= 40
子任务3:无限制

分析:我们由字符串a和b的一一对应关系,可以推出每个字母对应的的破解字母,例如给你两个长度相同的字符串a,b,现在已知b是a编码之后的结果
比如a = "CAT", b = "DOG", 那么D其实是C,O其实是A,G其实是T。依据“一一对应”原则可以知道,每个字母只能对应一个破解字母。如果对应多个,那么这肯定是无法破解的。我们可以先统计字符串B中每个字母出现次数,再统计字符串A中每个字母出现次数,由次数从小到大进行排序,检查从A到Z每个stra[i]是否等于strb[i],只要有一个不等于,那么这肯定是不合法的无法破解,直接输出@即可。

       如果合法的话,我们再看待破解的字符串中每个字符是否都能在字符串B中找到。那么这个字符串就可以破解了,如果有找不到的,我们还要再分情况讨论。如果在字符串B中能找到25个不同的字母的破解字母,我们就可以推测出剩下一个未出现字母的破解字母,这也是样例3给我们的提示,这样我们同样能够对待破解字符串进行破解,剩下的情况就无法破解了。比如有两个找不到的字母我们就无法推出其中一个字母的破解字母是谁。

#include<stdio.h>
#include<string.h>
typedef long long ll;
const int M=2e2+5;
char stra[M],strb[M],str[M];
ll i,j,k,size1,size2,STA[M],STB[M],sum=0,ta=0,tb=0,t=0;
void mysort(ll *a,ll n);//定义冒泡排序,本来想用sort排序,但总是被WA掉,只好用这个了
int main()
{
    scanf("%s",stra);//输入字符串A
    scanf("%s",strb);//输入字符串B
    size1=strlen(stra);
    for(i=0;i<size1;i++)//统计26个字母在字符串A和字符串B中每个字母出现的次数
    {
        STA[stra[i]]++;STB[strb[i]]++;
    }
    for(i='A';i<='Z';i++)//统计26个字母有多少个在字符串B中出现过
    {
        if(STB[i]!=0)
        sum++;
    }
    if(sum==25)//如果只有一个字母没有出现过,我们同样可以推测出没出现的字母和对应的破解字母
    {
        for(i='A';i<='Z';i++)
        {
            if(STA[i]==0)
                ta=i;
            if(STB[i]==0)
                tb=i;
        }
    }
    scanf("%s",str);
    size2=strlen(str);
    mysort(STA,91);
    mysort(STB,91);
    for(i='A';i<='Z';i++)
    {
        if(STA[i]!=STB[i])//检查字符串B与字符串A中字母是否一一对应
        {
            printf("@\n");//只要有一组不对应就直接输出@结束
            return 0;
        }
    }
    for(j=0;j<size2;j++)
    {
        for(i=0;i<size1;i++)
        {
            if(strb[i]==str[j])//检查待破解字符串中每个字母是否在字符串B中能找到
            {
                t++;
                break;
            }
        }
    }
    if(t==size2)//如果都能找到,就进行一一对应破解
    {
        for(j=0;j<size2;j++)
            for(i=0;i<size1;i++)
            {
                if(strb[i]==str[j])
                {
                    str[j]=stra[i];
                    break;
                }
            }
    }
    else if(sum==25)//如果有找不到的但是能通过已破解的25个字母推测出剩下一个字母,那么也可以
    {                                     //进行破解
        for(j=0;j<size2;j++)
            for(i=0;i<size1;i++)
            {
                if(strb[i]==str[j])
                {
                    str[j]=stra[i];
                    break;
                }
                else if(str[j]==tb)
                {
                    str[j]=ta;
                    break;
                }
            }
    }
    else//剩下情况就无法破解了直接输出@结束即可
    {
         printf("@\n");
            return 0;
    }
    for(i=0;i<size2;i++)//输出破解后的字符串
    {
        printf("%c",str[i]);
    }
    printf("\n");
}
void mysort(ll *a,ll n)//定义冒泡排序函数
{
    int t;
    for (int j=0;j<n-1;j++)
    {
        for (int i=0;i<n-j-1;i++)
        {
            if(a[i]>a[i+1])
            {
                t=a[i];
                a[i]=a[i+1];
                a[i+1]=t;
            }
        }
    }
}

 

### 牛客网1001题字符串展开算法实现 #### 题目解析 题目要求对给定的字符串按照特定规则进行扩展。具体来说,输入中的连字符 `-` 表示一段连续范围内的字符或数字需要被替换为其完整的序列形式。例如 `a-c` 应该转换为 `abc`。 根据已知条件[^2]和示例数据[^3],可以总结如下规则: - 如果两个字母之间存在连字符,则按 ASCII 值从小到大填充中间缺失的部分。 - 数字之间的连字符同样适用上述逻辑。 - 连续多个连字符只保留第一个作为分隔符。 - 扩展部分可能重复多次,由参数控制其重复次数。 以下是基于这些规则的一种通用解决方案: --- #### 解决方案 ```cpp #include <iostream> #include <string> using namespace std; // 判断是否为字母 bool isLetter(char c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); } // 判断是否为数字 bool isDigit(char c) { return c >= '0' && c <= '9'; } // 展开函数 void expandString(int p1, int p2, int p3, const string& inputStr) { string result; size_t i = 0; while (i < inputStr.length()) { char startChar = inputStr[i]; // 跳过当前字符直到找到下一个有效位置 if (!isLetter(startChar) && !isDigit(startChar)) { result += startChar; ++i; continue; } // 查找是否有 '-' 并定位结束字符 bool hasDash = false; char endChar = '\0'; for (size_t j = i + 1; j < inputStr.length(); ++j) { if (inputStr[j] == '-') { hasDash = true; continue; } else if ((hasDash && (isLetter(inputStr[j]) || isDigit(inputStr[j])))) { endChar = inputStr[j]; break; } } if (endChar != '\0') { // 存在合法区间 if (startChar <= endChar) { for (char k = startChar; k <= endChar; ++k) { result.append(p2, k); // 添加指定数量次 } } else { for (char k = startChar; k >= endChar; --k) { result.append(p2, k); } } // 移动指针跳过处理过的部分 i += distance(result.end() - p2 * abs(endChar - startChar)); } else { result += startChar; } ++i; } cout << result.substr(0, min((int)p1 * p3, (int)result.size())) << endl; } ``` --- #### 实现细节说明 1. **辅助判断方法** 定义了两个简单的布尔型函数用于检测字符是否属于字母或者数字类别[^1]。这有助于后续区分不同类型的子串并分别处理它们的行为模式。 2. **核心循环结构** 主要通过外层循环逐一遍历整个原始字符串,并利用内部嵌套查找机制来识别潜在的目标区域及其边界值。 3. **动态调整输出长度** 结合三个外部传入整数变量 \(p_1\),\(p_2\), 和 \(p_3\) 来决定最终结果截取片段的具体尺寸以及每单位元素复制频率。 4. **异常情况考虑** 对于不构成任何可操作区间的单个独立符号直接附加至累积缓冲区内;同时确保不会因为非法索引访问引发崩溃风险。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值