PAT甲级刷题笔记(7)

1027 火星颜色
本题本质上是把3个十进制数字转化为13进制下的数字输出。由于输入范围在0-168之间,只需把十进制数字除以13和对13取余后的结果输出即可。

#include<cstdio>

void transferRadix(int a){
    if(a/13<=9){
        printf("%d",a/13);
    }else{
        int x=a/13-10;
        printf("%c",'A'+x);
    }
    if(a%13<=9){
        printf("%d",a%13);
    }else{
        int x=a%13-10;
        printf("%c",'A'+x);
    }
}

int main(){
    int a,b,c;
    scanf("%d%d%d",&a,&b,&c);
    printf("#");
    transferRadix(a);
    transferRadix(b);
    transferRadix(c);
    return 0;
}

当然,还可以把13进制转化为数组,根据下标对应输出更简洁。

#include<cstdio>

char radix[14]={"0123456789ABC"};
int main(){  
    printf("#");
    for(int i=0;i<3;i++){
        int num;
        scanf("%d",&num);
        printf("%c%c",radix[num/13],radix[num%13]);
    }
    return 0;
}

语法:字符串数组,可以直接用字符串赋值,不必一个个字符赋值

1021 最深的根
(1)要判断图是否有环,有环的话需要判断有几个连通分量;可以用深度遍历算法,访问完所有结点调用DFS函数的次数即为连通分量个数
(2)若无环,则要找到使树具有最大深度的根节点并按序输出;如果仅调用一次DFS,则是树,进行第二次遍历,逐步更新找到最大深度,并将可能的根结点存入set中。

#include<cstdio>
#include<set>
#include<cstring>
using namespace std;
const int maxn=10010;
int G[maxn][maxn]={0};
bool isFind[maxn]={false};
int n,maxDepth=1;
set<int> root;

void DFS2(int u,int depth){
    //printf("访问结点%d,深度为%d\n",u,depth);
    isFind[u]=true;//u结点被访问
    if(depth==maxDepth) {
        root.insert(u);
    }else if(depth>maxDepth){
        root.clear();
        maxDepth=depth;
        root.insert(u);
    }
    for(int v=1;v<=n;v++){
        if(G[u][v]==1&&isFind[v]==false){//u可以到达v,且v没被访问
            DFS2(v,depth+1);
        }
    }
}

int main(){
    
    scanf("%d",&n);
    int a,b;
    for(int i=1;i<n;i++){
        scanf("%d%d",&a,&b);
        G[a][b]=G[b][a]=1;
    }
    int k=0;
    for(int u=1;u<=n;u++){
        if(isFind[u]==false){
            DFS2(u,1);
            k++;
        }
    }
    //printf("k=%d\n",k);
    root.clear();
    if(k>1){
        printf("Error: %d components",k);
        return 0;
    }
    for(int u=1;u<=n;u++){
        memset(isFind,0,sizeof(isFind));
        /*
        for(int i=1;i<=n;i++){
            isFind[i]=false;
        }
        */
        DFS2(u,1);
    }
    //printf("maxDepth=%d\n",maxDepth);
    for(set<int>::iterator it=root.begin();it!=root.end();it++){
        printf("%d\n",*it);
    }
    return 0;
}


为保证每个结点都能按最大深度方式遍历到,每次要重置遍历数组,不过这导致我在某个测试点超时。如何更简便的找到这些合适的根结点呢?
这里使用了一个结论:先任意选择一个点作为根节点,设其能到达最深的顶点集合为A,再从A中任选一个作为根节点,设其能到达最深的顶点集合为B,则树高最大顶点为A和B的集合。

#include<cstdio>
#include<set>
#include<vector>
#include<cstring>
using namespace std;
const int maxn=10010;
int G[maxn][maxn]={0};
bool isFind[maxn]={false};
int n,maxDepth=1;
vector<int> temp;//存储临时可能根节点
set<int> root;

void DFS(int u,int depth){
    //printf("访问结点%d,深度为%d\n",u,depth);
    isFind[u]=true;//u结点被访问
    if(depth==maxDepth) {
        temp.push_back(u);
    }else if(depth>maxDepth){//更新最大深度和对应结点
        temp.clear();
        maxDepth=depth;
        temp.push_back(u);
    }
    for(int v=1;v<=n;v++){
        if(G[u][v]==1&&isFind[v]==false){//u可以到达v,且v没被访问
            DFS(v,depth+1);
        }
    }
}

int main(){
    
    scanf("%d",&n);
    int a,b;
    for(int i=1;i<n;i++){
        scanf("%d%d",&a,&b);
        G[a][b]=G[b][a]=1;
    }
    int k=0,s1;
    for(int u=1;u<=n;u++){
        if(isFind[u]==false){
            DFS(u,1);
            if(u==1){
                if(temp.size()!=0) s1=temp[0];//取当前深度最深结点中任意一个作为下次遍历的根节点
                for(int i=0;i<temp.size();i++){//把当前深度最大结点集合加入root
                    root.insert(temp[i]);
                }
            }
            k++;
        }
    }    
    if(k>1){
        printf("Error: %d components",k);
        return 0;
    }
    memset(isFind,0,sizeof(isFind));//重置访问数组
    temp.clear();
    maxDepth=0;
    DFS(s1,1);//再次调用,确定集合B
    for(int i=0;i<temp.size();i++){//把集合B也加入到root中
        root.insert(temp[i]);
    }
    for(auto it=root.begin();it!=root.end();it++){
        printf("%d\n",*it);
    }
    return 0;
}

语法:(1)注意memset和fill的用法区别,memset是按字节赋值,如

memset(isFind,0,sizeof(isFind))

fill则是对一个个数组单元赋值:

fiil(isFind,ifFind+maxn,false);

(2)使用set可以自动排序去重,有时比vector更方便,其访问可以直接用auto,不必写复杂的迭代器

106 多项式乘法(1009)
多项式乘法可以分为两步,(1)逐项相乘;(2)合并同类项
可以定义多项式结构体存储多项式,再读入第2个多项式每一项时进行相乘;
合并过程,可以建立一个map,从指数映射到其系数
输出时要注意:(1)先去除不为0的项;(2)map是升序的,所以要倒序输出

#include<cstdio>
#include<map>
using namespace std;

struct polynomial{
    int exp;
    double coef;
}pol[10],p2;

map<int,double> result;
int main(){
    int k1,k2;//多项式项数
    scanf("%d",&k1);
    for(int i=0;i<k1;i++){//读入第一个多项式
        scanf("%d%lf",&pol[i].exp,&pol[i].coef);
    }
    int Exp;
    double Coef;
    scanf("%d",&k2);
    for(int i=0;i<k2;i++){//读入第二个多项式
        scanf("%d%lf",&p2.exp,&p2.coef);
        //printf("p2指数项为%d,系数项为%.1lf\n",p2.exp,p2.coef);
        for(int j=0;j<k1;j++){
            Exp=p2.exp+pol[j].exp;
            Coef=p2.coef*pol[j].coef;
            //printf("指数项为%d,系数项为%.1lf\n",Exp,Coef);
            auto it=result.find(Exp);
            if(it==result.end()){//该项第一次出现
                result[Exp]=Coef;
            }else{
                result[Exp]+=Coef;
            }            
        }
    }
    
    map<int,double>::reverse_iterator it;
    for(it=result.rbegin();it!=result.rend();it++){
        if(it->second==0){//先去除系数为0的项
            result.erase(it->first);
        }
    }
    printf("%d",result.size());
    for(it=result.rbegin();it!=result.rend();it++){
        
            printf(" %d %.1lf",it->first,it->second);
        
    }
    return 0;
}

语法:反向遍历map的方法:

map<int,double>::reverse_iterator it;
    for(it=result.rbegin();it!=result.rend();it++)

当然,注意到本题最大系数仅为1000,相乘后不会超过2000,也可以用辅助存储结果,输出其中不为0的项即可

#include<cstdio>
using namespace std;
const int maxn=1001;

int main(){
    int n1,n2;
    double arr[maxn]={0.0},ans[2*maxn]={0.0};//结果数组最大可达到2000,要多开内存
    scanf("%d",&n1);
    int exp;
    double coef;
    for(int i=0;i<n1;i++){
        scanf("%d%lf",&exp,&coef);
        arr[exp]=coef;
    }
    scanf("%d",&n2);
    for(int j=0;j<n2;j++){
        scanf("%d%lf",&exp,&coef);
        for(int i=0;i<maxn;i++){
            ans[i+exp]+=arr[i]*coef;
        }
    }
    int cnt=0;
    for(int i=0;i<2*maxn;i++){
        if(ans[i]!=0.0) cnt++;
    }
    printf("%d",cnt);
    for(int i=2*maxn-1;i>=0;i--){
        if(ans[i]!=0.0){
            printf(" %d %.1lf",i,ans[i]);
        }
    }
    return 0;
}

107 乒乓球(1026)
本题要求模拟排队打乒乓球的过程。难点在于有VIP球桌和球员。
思路:
1、建立球员和球桌的结构体,表明其时间信息和是否是VIP;
2、读入球员和球桌信息,球员按抵达时间排序;
3、按球员到来顺序和VIP条件分配桌子,分以下情况讨论:
设最早空闲桌子为idx,
1)如果idx是VIP桌,且当前队首为VIP球员,则idx给它
2)如果idx是VIP桌,当前队首不是VIP,则要看在idx空闲前,是否后续有VIP球员抵达,若有,让VIP插队获得idx
3)如果idx是普通桌,当前队首不是VIP,idx给它
4)如果idx是普通桌,当前队首是VIP,则要在这名VIP球员到达前,检查是否又有VIP桌子空闲,若有,则VIP球员去VIP桌,否则,去idx。
从上面看出,球员到达队列需要两个指针,一个i指向队首,一个VIPi指向下一个VIP球员

#include<cstdio>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
const int INF=100000000;
const int maxk=110;
struct Player{//球员
    int arriveTime,startTime,serveTime;//抵达时间、开始训练时间、训练时间
    bool isVIP;//是否是VIP
};
vector<Player> player;//由于想要直接把21点和来的运动员直接排出,所以不用数组而用vector
struct Table{
    int endTime,numServe=0;//当前服务结束时间,服务人数
    bool isVIP;
}table[maxk];

bool cmpArriveTime(Player x,Player y){
    return x.arriveTime<y.arriveTime;
}

bool cmpStartTime(Player x,Player y){
    return x.startTime<y.startTime;
}

int nextVIPPlayer(int VIPi){//寻找下一个VIP球员
    VIPi++;//先从当前VIP往后已一个
    while(VIPi<player.size()&&player[VIPi].isVIP==0){
        VIPi++;
    }
    return VIPi;
}

//把球桌pID分给球员tID
void allotTable(int pID,int tID){
    if(player[pID].arriveTime<=table[tID].endTime){//球员先到,更新其开始时间为桌子空闲时间
        player[pID].startTime=table[tID].endTime;
    }else{//球桌先空
        player[pID].startTime=player[pID].arriveTime;
    }
    //更新球桌训练结束时间,服务人数+1
    table[tID].endTime=player[pID].startTime+player[pID].serveTime;
    table[tID].numServe++;
}

int main(){
    int n;
    scanf("%d",&n);
    int hh,mm,ss,Times,trainTime,isVIP;
    int stTime=8*3600,edTime=21*3600;//开门和闭馆时间
    Player newplayer;
    for(int i=0;i<n;i++){
        scanf("%d:%d:%d %d %d",&hh,&mm,&ss,&trainTime,&isVIP);
        Times=hh*3600+mm*60+ss;        
        if(Times>=edTime) {
            //printf("Times=%d\n",Times);
            continue;//闭馆时间后才来,直接跳过,不考虑
        }
        newplayer.arriveTime=Times;
        newplayer.startTime=edTime;//先初始化开始时间为21点
        if(trainTime>120){//训练时间大于2h,压缩成2h
            trainTime=120*60;
        }else{
            trainTime*=60;
        }
        newplayer.serveTime=trainTime;
        newplayer.isVIP=isVIP;
        player.push_back(newplayer);//加入球员队列中
    }
    //printf("球员数%d\n",player.size());
    int k,m;//球桌数和VIP桌数
    scanf("%d%d",&k,&m);
    int VIPTable;//VIP桌子的号码
    for(int i=0;i<m;i++){//记录VIP桌子
        scanf("%d",&VIPTable);
        table[VIPTable].isVIP=true;
    }
    sort(player.begin(),player.end(),cmpArriveTime);//按到达时间对球员排序   
    int i=0,VIPi=-1;//i指向当前队首球员,VIPi指向当前最前的VIP球员
    VIPi=nextVIPPlayer(VIPi);
    while(i<player.size()){//遍历球员列表
        int idx=-1,minEndTIme=INF;
        for(int j=1;j<=k;j++){
            if(table[j].endTime<minEndTIme){//寻找当前最早空闲的桌子idx
                idx=j;
                minEndTIme=table[j].endTime;
            }
        }
        if(table[idx].endTime>=edTime) break;//已到关门时间,结束
        if(player[i].isVIP==1&&i<VIPi){
            //i号是VIP球员,但VIPi>i,说明它已经安排过了
            i++;
            continue;
        }
        //分4种情况讨论
        if(table[idx].isVIP==1){
            if(player[i].isVIP==1){//情况1:球员和球桌都是VIP
                allotTable(i,idx);
                if(VIPi==i) VIPi=nextVIPPlayer(VIPi);//找到下一个VIP球员
                i++;
            }else{//情况2球桌都是VIP,球员不是VIP
             //如果当前队首的VIP球员在VIP空闲前到,则插队获得
                if(VIPi<player.size()&&player[VIPi].arriveTime<=table[idx].endTime){
                    allotTable(VIPi,idx);
                    VIPi=nextVIPPlayer(VIPi);
                }else{
                    allotTable(i,idx);
                    i++;
                }
            }
        }else{
            if(player[i].isVIP==0){//情况3:球桌不是VIP,球员不是VIP
                allotTable(i,idx);
                i++;
            }else{//情况4:球桌不是VIP,球员是VIP
                //找到最早空闲VIP球桌
                int VIPidx=-1,minVIPEndTime=INF;
                for(int j=1;j<=k;j++){
                    if(table[j].isVIP==1&&table[j].endTime<minVIPEndTime){
                        minVIPEndTime=table[j].endTime;
                        VIPidx=j;
                    }
                }
                //若最早空闲VIP球桌,且空闲时间比球员来的时间早,则分给它
                if(VIPidx!=-1&&player[i].arriveTime>=table[VIPidx].endTime){
                    allotTable(i,VIPidx);
                    if(VIPi==i) VIPi=nextVIPPlayer(VIPi);
                    i++;
                }else{
                    allotTable(i,idx);
                    if(VIPi==i) VIPi=nextVIPPlayer(VIPi);
                    i++;
                }
            }
            
        }
    }
    sort(player.begin(),player.end(),cmpStartTime);
    for(int i=0;i<player.size()&&player[i].startTime<edTime;i++){
        int t1=player[i].arriveTime,t2=player[i].startTime;
        printf("%02d:%02d:%02d ",t1/3600,t1%3600/60,t1%60);
        printf("%02d:%02d:%02d ",t2/3600,t2%3600/60,t2%60);
        printf("%.0f\n",round((t2-t1)/60.0));//服务时间
    }
    for(int i=1;i<=k;i++){
        printf("%d",table[i].numServe);
        if(i<k) printf(" ");
    }
    return 0;
}

108 找平均数(1108)
本题要求一组数字的平均数,关键在于筛除非法输入。合法的输入要求:最多只能有两位小数的数字。先用字符串读入输入数字,再审查每一位(除了负号)),看是否是0-9之间的数字,如果有小数点,要求后面数字不能超过2位。之后再将合法数字从字符串转化为数字存储计算。

#include<cstdio>
#include<vector>
using namespace std;
vector<double> num;

bool isLegal(char s[]){
    int i=0;
    int decimal=0,numPoint=0;//统计小数点后位数和小数点个数
    if(s[i]=='-') i++;
    while(s[i]!='\0'){
        if(s[i]>='0'&&s[i]<='9'){
            if(numPoint==1) decimal++;
            if(decimal>2) return false;
        }
        else if(s[i]=='.'){
            numPoint++;
            if(numPoint>1) return false;
        }
        else{
            return false;
        }
        i++;
    }
    return true;
}

double change(char s[]){
    int i=0;
    double ans=0;
    if(s[i]=='-') i++;
    while(s[i]!='\0'&&s[i]!='.'){
        ans=ans*10+s[i]-'0';
        i++;
    }
    if(s[i]=='.'){        
        i++;
        if(s[i]!='\0') ans+=0.1*(s[i]-'0');
        if(s[++i]!='\0'){
            //printf("%s有2位小数,i=%d\n",s,i);
            ans+=0.01*(s[i]-'0');
        }
    }
    if(s[0]=='-') ans*=-1;
    return ans;
}

int main(){
    
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        char str[100];
        scanf("%s",str);
        if(isLegal(str)){//合法数字
            double a=change(str);
            if(a>1000||a<-1000) {
                printf("ERROR: %s is not a legal number\n",str);
                continue;
            }
            num.push_back(a);
        }else{
            printf("ERROR: %s is not a legal number\n",str);            
        }
    }
    if(num.size()==0){
        printf("The average of 0 numbers is Undefined");
    }else{
        double sum=0;
        int size=num.size();
        for(int i=0;i<size;i++){
            //printf("%.2lf\n",num[i]);
            sum+=num[i];
        }
        if(size==1){
            printf("The average of %d number is %.2lf",size,sum/size);
        }
        else {
            printf("The average of %d numbers is %.2lf",size,sum/size);
        }
    }
    return 0;
}

也可以用sscanf和sprintf解决

#include<cstdio>
#include<string.h>
using namespace std;

int main(){    
    int n,cnt=0;
    scanf("%d",&n);
    char a[50],b[50];
    double sum=0,temp;
    for(int i=0;i<n;i++){
        scanf("%s",a);
        sscanf(a,"%lf",&temp);//读入字符串a中的浮点数
        sprintf(b,"%.2f",temp);//把浮点数temp取2位小数,存入字符串b
        int flag=0;
        for(int j=0;j<strlen(a);j++){//排出小数点多余2位的情况
            if(a[j]!=b[j]) {
                flag=1;
                break;
            }
        }
        if(flag||temp<-1000||temp>1000){
            printf("ERROR: %s is not a legal number\n",a);
            continue;
        }else{
            sum+=temp;
            cnt++;
        }
    }
    if(cnt==1){
        printf("The average of 1 number is %.2lf",sum);
    }else if(cnt>1){
        printf("The average of %d numbers is %.2lf",cnt,sum/cnt);
    }else{
        printf("The average of 0 numbers is Undefined");
    }
    return 0;
}

语法:(1)sscanf的用法:sscanf() - 从一个字符串中读进与指定格式相符的数据.

如:取仅包含指定字符集的字符串。如在下例中,取仅包含1到9和小写字母的字符串。
  sscanf("123456abcdedfBCDEF", "%[1-9a-z]", buf);
  printf("%s\n", buf);
  结果为:123456abcdedf

(2)sprintf的用法:

int sprintf( char *buffer, const char *format, [ argument] … );

参数列表:

  buffer:char型指针,指向将要写入的字符串的缓冲区。

  format:char型指针,指向的内存里面存放的将要格式字符串。

  [argument]...:可选参数,可以是任何类型的数据。

  返回值:字符串长度(strlen)

109 集体照(1109)
本题要根据身高确定每个人在集体照中的位置。思路:
(1)定义结构体存储每个人的信息,之后按身高和姓名顺序排序;
(2)每个人的位置信息由行号和列号确定。根据总人数和行数可以确定每行人数,在根据规则确定每行位置即可。

#include<cstdio>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn=10010;
struct Man{
    char name[10];
    int height;//身高
    int No;//在集体照中的序号
}man[maxn];

bool cmpHeight(Man x,Man y){//按身高和姓名排序
    if(x.height!=y.height) return x.height>y.height;
    else return strcmp(x.name,y.name)<0;
}

bool cmpNo(Man x,Man y){
    return x.No<y.No;
}

int main(){
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++){
        scanf("%s %d",man[i].name,&man[i].height);
    }
    sort(man,man+n,cmpHeight);
    int extra=n%k;//每行人数和最后一行多余人数
    int No=0,cnt=0;//集体照中的序号,已遍历的前i-1行人数
    for(int i=0;i<k;i++){
        int rowNum=n/k;//正常每行人数
        if(i==0) rowNum+=extra;//最后一行加上多余人数
        int mid=rowNum/2+1;//当前行队中元素时第几位        
        for(int j=0;j<rowNum;j++){
            if(j%2==0) man[No++].No=cnt+mid+j/2;//排在中间元素的右边
            else man[No++].No=cnt+mid-(j+1)/2;//排在中间元素的左边
        }
        cnt+=rowNum;
    }
    sort(man,man+n,cmpNo);
    No=0;
    for(int i=0;i<k;i++){
        int rowNum=n/k;//正常每行人数
        if(i==0) rowNum+=extra;//最后一行加上多余人数
        for(int j=0;j<rowNum;j++){
            if(j>0) printf(" ");
            printf("%s",man[No].name);
            No++;
        }
        printf("\n");
    }
    return 0;
}

110 完全二叉树(110)
本题要判断给定的树是否是完全二叉树。
(1)用静态树存储结点信息,未被读到的结点即为树的根结点
(2)深度遍历,确定树的高度h,之后层序遍历统计1-h-1层的结点数是否符合要求,最后一层是否是顺序铺满的。从而判断是否是完全二叉树.
但是用这样的方法显得很繁琐。注意到完全二叉树的性质,设根节点序号为i(从1开始)则左子树序号为2*i,右子树为2*i+1。用这样的方法给树结点编号,若最后序号大于节点数,则说明不是完全二叉树。

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=25;
struct Node{
    int lchild,rchild;
}node[maxn];

bool isRoot[maxn]={false};
int maxi=0,last;//统计最大序号和对应结点序号
void DFS(int root,int i){
    if(i>maxi){
        maxi=i;
        last=root;
    }    
    if(node[root].lchild!=-1) DFS(node[root].lchild,2*i);
    if(node[root].rchild!=-1) DFS(node[root].rchild,2*i+1);
}

int main(){
    int n;
    scanf("%d",&n);
    string a,b;
    for(int i=0;i<n;i++){
        cin>>a>>b;
        if(a=="-"){
            node[i].lchild=-1;
        }else{
            node[i].lchild=stoi(a);
            isRoot[stoi(a)]=1;
        }
        if(b=="-"){
            node[i].rchild=-1;
        }else{            
            node[i].rchild=stoi(b);
            isRoot[stoi(b)]=1;
        }
    }
    
    int root;
    for(int i=0;i<n;i++){
        if(isRoot[i]==false) {
            root=i;
            break;
        }
    }    
    DFS(root,1);    
    if(maxi>n){
        printf("NO %d",root);
    }else{
        printf("YES %d",last);
    }
    
    return 0;
}

语法:stoi():把数字字符串转变为int输出,头文件#include<cstring>,参数为string类型

类似的还有atoi(),参数是char* str

112 卡住的键盘(112)
本题要求判断键盘上卡住的键,按1次会重复输出k次。将判断的键按出现先后顺序输出,
并把去掉重复后的结果输出。
(1)寻找坏键。将每个字符与前一个字符相比较,如果相同,cnt++,继续比较;否则置为1
cnt%k==0,说明是坏键,因为有的键可能本身就被连按了几次。
考虑到有些字母开始被认为是坏键,后面发现不是,所以建立一个map<char,bool>的映射存储
相应的:还有前面认为不是坏键则它一定没坏,后面如果出现大量重复也不能认为出现了坏键,
所以也要用sureNoBroken标记出来。
(2)输出坏键,由于需要按发现顺序输出,所以要遍历字符串,输出确定是坏键的字符,同时,输出后存入set中,避免重复输出。

#include<cstdio>
#include<set>
#include<map>
#include<string.h>
using namespace std;
bool sureNoBroken[256]={false};
map<char,bool> mp;
set<char> printed;
int main(){
    int k;
    scanf("%d",&k);
    char s[1010];
    scanf("%s",s);
    int len=strlen(s);
    char pre='#';
    int cnt=1;
    for(int i=0;i<len;i++){
        if(s[i]==pre){//出现重复,开始统计
            cnt++;
        }else{//不同
            if(cnt%k!=0){//cnt不能整除k,所以pre一定不是坏键
                //printf("cnt=%d,pre=%c\n",cnt,pre);
                sureNoBroken[pre]=true;
            }
            cnt=1;
        }
        mp[s[i]]=(cnt%k==0);//先把初步判断结果存入mp
        pre=s[i];
    }
    for(int i=0;i<len;i++){
        if(sureNoBroken[s[i]]==true){//确定不是快键的要修正
            mp[s[i]]=false;
        }
    }
    for(int i=0;i<len;i++){//输出坏键
        if(mp[s[i]]&&printed.find(s[i])==printed.end()){//mp中确定是坏键,且还未输出过
            printf("%c",s[i]);
            printed.insert(s[i]);//输出过的保存,避免重复
        }
    }
    printf("\n");
    for(int i=0;i<len;i++){
        printf("%c",s[i]);
        if(mp[s[i]]){//坏键跳过重复部分
            i=i+k-1;
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值