HAPPY训练赛——Complete the Word

先说一下思路:
这种做法有部分测试用例过不去。想了很久不知道原因,求高手指点。
题目是要找连续的长度为26的子串,并且这个子串包含A-Z所有的字母(当然肯定是每个字母只出现一次)。
我的思路有点类似与上一篇文章那个求最大子序列和的在线法。
首先我开一个数组用来记每个字母有没有出现过,从第一个开始遍历,分两种情况,要么遇到‘?’,要么遇到字母。如果遇到字母,对每一个字母若出现过,那么把上一个位置(假设是位置i)的这个字母以及以前的字母全都标记为未出现过,即扔掉从i位置到上一次i(这里注意,上一次的i每次都会用lasti记录,第一次lasti肯定是0,以后每次都是lasti=i+1)位置之间的序列,只保留余下的部分;接着把当前访问的这个字母标记为一出现,总数加一。
如果遇到问号就记录数目即可。
途中如果字母数加问号数等于26,那么就可以退出循环了,因为已经找到了所求子串。
如果符合条件,则填充的时候,把没出现过的依次填进去就好(一定是从lasti填到lasti+26),然后再从头遍历一遍,把其他的‘?’都填成任意一个字母即可。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<set>
using namespace std;

int main(){
    string a;//记原字符串
    cin >> a;
    int cnt = 0,sum = 0;
    int len = a.length();
    int c[200];//记每个字母的位置
    int book[26]={};//记已出现的字母
    int i=0;
    int lastj=0;//上一次重复出现的位置
    while(len--){
        if(a[i]=='?'){
            cnt++;
            i++;
        }
        else{
            if(book[a[i]-65]==1){//处理重复以前的字母
                int j = c[a[i]];//
                for(int k=j;k>=lastj;k--){
                    if(a[k]=='?'){
                        cnt--;
                    }else{
                        book[a[k]-65]=0;
                        sum--;
                    }
                }
                lastj = j+1;//
            }
            c[a[i]]=i;
            book[a[i++]-65]=1;
            sum++;
            if(sum+cnt >= 26)//子串已找到
                break;
        }
    }
    int lj=0;
    for(int k=lastj;k<lastj+26;k++){//填“?”
        if(a[k]=='?'){
            int j;
            for(j=lj;j<26;j++){
                if(book[j]==0)
                    break;
            }
            a[k]=j+65;
            lj=j+1;//
        }
    }
    for(int j=0;j<a.length();j++){
        if(a[j]=='?')
            a[j]='A';
    }
    if(sum+cnt>=26)
        cout << a;
    else
        cout << -1;
    return 0;
}

下面是简单的暴力求解,两层for循环解决问题。
思路很简单,把每一组26的子串都跑一遍,有重复就break,直到找到没有重复的26个连续子串(‘?’不算重复)。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<set>
using namespace std;

int main(){
    string a;
    cin >> a;
    int book[26]={};
    int i,j;
    int flag=0;
    for(i=0;i<a.length();i++){
        flag=0;
        for(j=i;j<i+26;j++){
            if(a[j]!='?'){
                if(book[a[j]-65]==1){
                    flag=1;
                    break;
                }
                book[a[j]-65]=1;
            }
        }
        if(flag==0){
            flag=2;
            break;
        }
        memset(book,0,26*sizeof(int));
    }
    int m=0;
    if(flag==2){
        for(int k=i;k<i+26;k++){
            if(a[k]=='?'){
                for(int h=m;h<26;h++){
                    if(book[h]==0){
                        a[k]=h+65;
                        m=h+1;
                        break;
                    }
                }
            }
        }
        for(int k=0;k>a.length();k++){
            if(a[k]=='?')
                a[k]='A';
        }
        cout << a;
    }else   cout << -1;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值