最近入手了《编程之美》,匠着,需常磨其器。我的“器”就是编程的能力,听说上面有很多有趣的问题,所以就入手了一本。磨磨脑子,练练编程。
如题:
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:思维一变,方法就变,节省了好多行代码。
所以说要常磨脑子。