编程之美-字符串移位包含的问题

          最近入手了《编程之美》,匠着,需常磨其器。我的“器”就是编程的能力,听说上面有很多有趣的问题,所以就入手了一本。磨磨脑子,练练编程。

      如题:

      3.1    字符串移位包含的问题

      给定两个字符串s1和s2,要求判定s2是否能够被s1做循环移位得到的字符串包含。例如,给定s1=AABCD和s2=CDAA,返回true;给定s1=ABCD和s2=ACBD,返回false。

      解法:

      一、解题需分两个关键:1、给s1做循环移位,2、判定s1是否包含s2 

             源代码:

            

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 #include<unistd.h>
  5 
  6 int main()
  7 {
  8    char s1[100] = "\0", s2[100] = "\0";
  9    char *string1 = NULL, *string1_1 = NULL, *string2 = NULL;
 10    int  s1_len = 0, s2_len = 0;
 11    int  i = 0, j = 0;
 12    int  flag = 0;
 13    char temp = '\0';
 14 
 15    printf("Please input the first string:\n");
 16    fgets(s1, 100, stdin);
 17    printf("Please input the second string:\n");
 18    fgets(s2, 100, stdin);
 19 
 20    s1_len = strlen(s1) - 1;//注意fgets在s1与s2后面会添加'\n',所以实际长度要减去1
 21    s2_len = strlen(s2) - 1;
 22 
 23    if(s2_len > s1_len)
 24    {
 25         printf("不包含");
 26         exit(1);
 27    }
 28    /*循环移位s1*/
 29    for(i = 0; i < s1_len; i++)
 30    {
 31         temp = s1[0];
 32         
 33         for(j = 0; j < (s1_len - 1); j++)
 34         {
 35             s1[j] = s1[j+1];
 36         }
 37 
 38         s1[s1_len - 1] = temp;
 39 
 40         /*检测s1是否包含s2*/
 41         string1 = s1;
 42         while(*string1 != '\n')//fegts在字符串后面添加了换行符后才是'\0'
 43         {
 44             string1_1 = string1;
 45             string2 = s2;
 46             flag = 0;
 47             while(*string2 == *string1_1)
 48             {
 49                 string2 ++;
 50                 string1_1 ++;
 51                 flag++;
 52                 if(s2_len == flag)
 53                 {
 54                     printf("%s包含%s\n",s1,s2);
 55                     exit(0);
 56                 }
 57              }
 58              string1 ++;
 59         }
 60    }
 61    printf("不包含\n");
 62    exit(0);
 63 }

       这是最笨的一种办法了。

       原书对该种解法给出的代码是:

       

  1 char src[] = "AABBCD";
  2 char des[] = "CDAA";
  3 
  4 int len = strlen(src);
  5 for(int i = 0; i < len; i++)
  6 {
  7     char tempchar = src[0];
  8     for(int j = 0; j < len - 1; j++)//依我的脾气,会加{}
  9         src[j] = src[j + 1];
 10     src[len - 1] = tempchar;
 11     if(strstr(src, des) == 0)//依我的脾气:if(0 == strstr(src, des))
 12     {
 13         return (true);
 14     }
 15 }
 16 return false;

      二、(第二种想法我没有想到,将原书的解释列在这里)

      以s1=ABCD为例,先分析对s1进行循环移位后的结果,如下所示:
       ABCD -> BCDA -> CDAB -> DABC -> ABCD...
      假设我们把前面移走的数据进行保留,会发现如下的规律:
       ABCD -> ABCDA -> ABCDAB -> ABCDABC -> ABCDABCD
       因此,可以看出对s1做循环移位所得到的字符串都将是字符串s1s1的子字符串。如果s2可以由s1循环移位得到,那么s1一定在s1s2上。至此我们将问题转换成考察s2是否在s1s1上,可通过一次strstr函数得到结果。例如若CDBA在ABCDABCD上,那么CDAB也可通过ABCD做循环移位得到(ABCD循环左移或循环右移两位)        
       比较简单,就不再奉上源码了。
       三、第三种解法就是s1不动,指向s1的指针动,比如:

       s1:   ABCD

       s2:   CDA

       当比较完C与D之后,指针就返回至S1的第一位,然后再进行比较。

      

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 
  5 int main(void)
  6 {
  7     char s1[100] = "\0", s2[100] = "\0";
  8     char *string1_1, *string1_2, *string2_1;
  9     int  flag = 0;
 10 
 11     printf("Please input the first string:\n");
 12     fgets(s1, 100, stdin);
 13     printf("Please input the second string:\n");
 14     fgets(s2, 100, stdin);
 15      
 16     string1_1 = s1;
 17     while(*string1_1 != '\n')
 18     {
 19         string1_2 = string1_1;
 20         string2_1 = s2;
 21         flag = 0; 
 22         while((*string1_2 == *string2_1))
 23         {
 24             string1_2++;
 25             string2_1++; 
 26             flag++;
 27             
 28             if('\n' == *string1_2)
 29             {
 30                 string1_2 = s1;
 31             }   
 32             
 33             if(flag == (strlen(s2) - 1))
 34             {
 35                 printf("包含\n");
 36                 exit(0);
 37             }   
 38         }   
 39         string1_1++;
 40     }
 41     printf("不包含\n");
 42     exit(0);
 43 }

             相较3与1:思维一变,方法就变,节省了好多行代码。

             所以说要常磨脑子。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值