NewCoder——玛雅人的密码【C语言】

在这里插入图片描述
在这里插入图片描述

【C语言】题解思路分析:
这道题是利用队列的数据结构,采用树的层次遍历思想来完成的。
1、首先,我们先构造一个队列

typedef struct Queen
{
    char **str;        //构建字符串数组
    int length;       //字符串的长度
    int front,rear;   //构建队首指针和队尾指针
    int len[20000];   //len数组的目的是为了来标记当前字符串的移位次数
}queen;

PS:关于字符串数组的指针建立原理以及指针数组数组指针的用法可以参见这篇文章,说实话我真心觉得总觉的很到位了【伙计们看这里】

2、关于在程序中遇到的入队出队代码我们先暂且略过,先介绍
程序思想的主体,层次遍历。

//层次遍历
int BFS(char *a,int N)  // a就是我们需要验证的字符串,N就是字符串的长度。
{
    queen q;   
    char *c;            //字符串c用来临时存放移位的字符串
    int i,j;
    int temp=100,start=0,end;
    init(&q,N);         //队列初始化
    add(&q,a);          //字符串入队
    q.len[0]=0;         //len在对应第一个字符串位置的时候是0,因为并没有发生移位,移位次数为0。
    c=malloc(char*)malloc(sizeof(char)*N);    //为字符串C动态分配N的大小空间。
    if(judge(a))        //先判断a是否包含2012
    return 0;
    while(temp !=q.rear) //若队不为空
    {
        temp= q.rear;   //用temp记录树的下一层遍历的开始位置,也就是这一层的结束位置。
        end=q.rear;     //end记录这一层的结束位置,也就是下一层的开始位置。
        for(i=star;i<end;i++)
        {
            for(j=0;j<N-1;i++) //这一层的循环是为了对当前字符串进行从第一位到第N-1位的不同相邻字符位移。
            {
                swap(q.str[i],c,j) //把q.str[i]的j和j+1位置的字符进行交换并且赋值给C。
                if(find(&q,c)!=1)  //如果在队列q中没有发现c一样的字符串
                {
                    q.len[q.rear-1]=q.len[i]+1; //并且把当前节点的字符串对应的标记数组len的位置替换成len[i]+1
                }                               //这是因为当前字符串是由q.str[i]位移1次得到的。
                if(judge(c))
                {
                    return q.len[q.rear-1];     //如果字符串c包含2012,那么返回它对应位置的位移次数
                }
            }
        }
        start=temp;    //如果找完了这一层还没找到,那么把队列的结束位置赋值给star,下一次从新的一层开始遍历查找。
    }
    return -1;        //层次遍历完这颗树依旧没有结果,那么返回-1。
}

在这里插入图片描述队列的情况如下:
在这里插入图片描述
以下就是全部的程序:

#include<stdio.h>
#include<string.h>
#include<malloc.h>
typedef struct Queen{
    char **str;
    int length;
    int front;int rear;
    int len[200000];
}queen;
void init(queen *q,int n)        //队列初始化
{
    q->front=0;
    q->rear=0;
    q->length=n;
    q->str=(char**)malloc(sizeof(char*)*200000);
}
void add(queen *q,char *Str)     //添加元素进队
{
    q->str[q->rear]=(char*)malloc(sizeof(char)*13);
    strcpy(q->str[q->rear++],Str);
}

int find(queen *q,char *str)
{
    int i;
    if(q->front==q->rear)          //若队列是空,把str加入到队列中去。
    {
        add(q,str);
        return 0;
    }
    for(i=q->front;i<q->rear;i++)  //从队尾到队头开始找
    {
        if(strcmp(q->str[i],str)==0) //在队列中如果找到这个元素就返回1
        return 1;
    }
    add(q,str);                      //如果没找到就把str加入到队列中
    return 0;
}
int judge(char *a)
{
    char *c;
    //int d;
    c=strstr(a,"2012");       //C 库函数 char *strstr(const char *haystack, const char *needle)
    if(c)                     //在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 '\0'。
    return 1;                 //如果是,则该函数返回 str1字符串从 str2第一次出现的位置开始到 str1结尾的字符串;否则,返回NULL。
    else
    return 0;

}
void swap(char *a,char *b,int i)   //字符串前一位和后一位互换
{
    char temp;
    strcpy(b,a);
    temp=b[i];
    b[i]=b[i+1];
    b[i+1]=temp;
}

int BFS(char *a,int N)           //层次遍历
{
    queen q;
    char *c;
    int i,j;
    int temp=100,start = 0,end;
    init(&q,N);
    add(&q,a);
    q.len[0]=0;
    c=(char*)malloc(sizeof(char)*N);    //建立一个N大小的字符串变量
    if(judge(a))                        //判断a是否是2012
    return 0;
    while(temp!=q.rear)
    {
        temp = q.rear;
        end = q.rear;
        for(i=start;i<end;i++)         //从star开始到end循环是树的一层
        {
            for(j=0;j<N-1;j++)         //把当前树的这一层的每一个节点所有相邻交换情况遍历,未出现的数入队,以便下一层的层次遍历
            {
              swap(q.str[i],c,j);      //把字符串q.str[i]中的j和j+1互换并赋值给C。
              if(find(&q,c)!=1)        //队列中是否存在过C,如果没有过
              {
                q.len[q.rear-1] = q.len[i] +1;  //把交换前的的数对应的len数组的位置的数增1
              }                                 //这一步骤是为了记录交换前的那个数经历了几次位移交换出现2012
              if(judge(c))            //如果C是2012
              return q.len[q.rear-1];  //返回这个数移动的次数
            }
        }
        start = temp;               //循环结束把队尾元素的位置返回给start,下一次循环从这个位置的节点再开始交换比较
    }
    return -1;
}
int main()
{
    int n;
    int i;
    char *c;
    while(scanf("%d",&n)!=EOF)
    {
        c=(char*)malloc(sizeof(char)*n);
        scanf("%s",c);
        if(n<4)
        {
            printf("-1\n");
            continue;
        }
        i=BFS(c,n);
        printf("%d\n",i);
        free(c);
     }
    return 0;
}

程序运行结果:
在这里插入图片描述
最后,对于不熟悉初始化以及入队和出队算法的童鞋们,我们复习一下元素的入队和出队算法:
队列初始化
基础代码:

//先构建一个顺序队列
typedef struct
{
   int data[200000];
   int front;
   int rear;
}Queue
void InitQueue(Queue &qu)
{
   qu.front=qu.rear=0;
}

题目中:

void init(queen *q,int n)
{
    q->front=0;
    q->rear=0;
    q->length=n;
    q->str=(char**)malloc(sizeof(char *)200000) //此处相当于建立200000行单元格,每个单元格存字符串
}

入队

int enQueue(Queue &qu,int x)
{
   if((qu.rear+1)%200000==qu.front) //这里考虑的是循环队列
   {
       return 0;
   }
   qu.rear=(qu.rear+1)%200000;
   qu.data[qu.rear]=x;
   return 1;
}

题目中:

void add(queen *q,char *Str)
{
    q->str[q->rear]=(char*)malloc(sizeof(char)*13);
    strcpy(q->str[q->rear++],Str);  //这里是先入队,再移动指针,一样的,只不过因为初始时,rear=0,所以不需要先++,再入队。
}

出队:

int deQueue(SqQueue &qu,int &x)
{
    if(qu.front==qu.rear)
    {
       return 0;
    }
    qu.front=(qu.front+1)%200000;
    x=qu.data[qu.front];
    return 1
}

再强调一下关于为什么结构体中建立字符串数组,因为当用C语言自带的函数进行比对的时候,这些函数只针对于字符串,如果建立成数组的话就比较麻烦了。比如:
strstr函数
strcmp函数
等等。。。。

PS: 本人蒟蒻一枚,所以写了很多细枝末节的地方,这份代码也是借鉴之后,只进行了注释工作,对于这版代码摘自牛客的大神。感谢yr亦然大神的代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值