[算法 笔记]字符串移位包含问题

  问题出自《编程之美》3.1 

  1 /* 2013.6.25
  2  * 问题:给定两个字符串s1和s2,要求判定给定字符串s2是否
  3  * 能够通过字符串s1循环移位得到的字符串包含。
  4  * 例如:
  5  * 1. s1 = AABCD,s2 = CDAA,则返回true;
  6  * 2. s1 = ABCD,s2 = ACBD,则返回false
  7  */
  8 #include <stdio.h>
  9 #include <string.h>
 10 #include <stdlib.h>
 11 
 12 enum { true = 1, false = 0 };
 13 
 14 /* 2013.6.25
 15  * 方式1:用s2[0]将字符串s1分为两个部分。
 16  * 第一部分:strcmp(s2, s1 + j, strlen(s1)-j) ,其中,j是s2[0] == s1[j]
 17  * 第二部分:strcmp(s2 + strlen(s1) - j, s1, strlen(s2) - strlen(s1) - j).
 18  * 时间复杂度:O( strlen(s1) * strlen(s2) ), 空间复杂度:O(1)
 19  */
 20 int CheckRotStr1( const char *s1, const char *s2 )
 21 {
 22     int start = 0;
 23     int nlen1, nlen2, tmpLen;
 24 
 25     if ( s1 == NULL || s1[0] == '\0'
 26         || s2 == NULL || s2[0] == '\0' )
 27     {
 28         printf( "Error for arguments!\n" );
 29         return -1;
 30     }
 31 
 32     // 查找s2[0]在s1中的位置
 33     nlen1 = strlen( s1 );
 34     nlen2 = strlen( s2 );
 35     while ( start < nlen1 )
 36     {
 37         if ( s2[0] == s1[start] )
 38             break;
 39 
 40         ++start;
 41     }
 42 
 43     if ( start == nlen1 )
 44         return false;
 45 
 46     tmpLen = nlen1 - start;
 47     if ( strncmp( s2, s1 + start, tmpLen ) == 0 )
 48     {
 49         if ( tmpLen == nlen2 )
 50             return true;
 51 
 52         start = tmpLen;
 53         tmpLen = nlen2 - tmpLen;
 54         if ( strncmp( s2 + start, s1, tmpLen ) == 0 )
 55             return true;
 56     }
 57 
 58     return false;
 59 }
 60 
 61 /* 2013.6.25
 62  * 方式2:拷贝一份s1填充到s1后面,然后查找s2是否为s1的子串。
 63  * 时间复杂度:O(strlen(s2)*strlen(s1)), 空间复杂度:O(2*strlen(s1))
 64  */
 65 int CheckRotStr2( const char *s1, const char *s2 )
 66 {
 67     char *newS1 = NULL;
 68     int nlen1, nlen2, start = 0;
 69 
 70     if ( s1 == NULL || s1[0] == '\0'
 71         || s2 == NULL || s2[0] == '\0' )
 72     {
 73         printf( "Error for arguments!\n" );
 74         return -1;
 75     }
 76 
 77     nlen1 = strlen( s1 );
 78     nlen2 = strlen( s2 );
 79     newS1 = (char *) malloc( nlen1 * 2 * sizeof( char ) + 1 );
 80     if ( newS1 == NULL )
 81     {
 82         printf( "Error for malloc!\n" );
 83         return -1;
 84     }
 85 
 86     // 拷贝字符串s1
 87     strncpy( newS1, s1, nlen1 );
 88     strncpy( newS1 + nlen1, s1, nlen1 );
 89     nlen1 <<= 1;
 90     newS1[nlen1] = '\0';
 91 
 92     // 查找s2[0]在newS1中的位置
 93     while ( start < nlen1 )
 94     {
 95         if ( s2[0] == newS1[start] )
 96             break;
 97 
 98         ++start;
 99     }
100 
101     if ( start == nlen1 )
102         return false;
103 
104     if ( strncmp( s2, newS1 + start, nlen2 ) == 0 )
105     {
106         free( newS1 );
107         return true;
108     }
109 
110     free( newS1 );
111     return false;
112 }
113 
114 /* 2013.6.25
115  * 方式3:思路和方式2一样,但是利用摩计算来省略拷贝问题
116  * 时间复杂度:O(strlen(s2)+strlen(s1)), 空间复杂度:O(1)
117  */
118 int CheckRotStr3( const char* s1, const char *s2 )
119 {
120     int nlen1, nlen2, start = 0;
121     int end, i = 0;
122 
123     if ( s1 == NULL || s1[0] == '\0'
124         || s2 == NULL || s2[0] == '\0' )
125     {
126         printf( "Error for arguments!\n" );
127         return -1;
128     }
129 
130     nlen1 = strlen( s1 );
131     nlen2 = strlen( s2 );
132 
133     // 查找s2[0]在newS1中的位置
134     while ( start < nlen1 )
135     {
136         if ( s2[0] == s1[start] )
137             break;
138 
139         ++start;
140     }
141 
142     if ( start == nlen1 )
143         return false;
144 
145     end = start + nlen1;
146     // 需要注意,如果nlen2超过nlen1的长度,则返回false。
147     while ( start < end && i < nlen2 )
148     {
149         int tmp = start % nlen1; // 利用摩计算消除了拷贝的需求
150 
151         if ( s2[i] != s1[tmp] )
152             break;
153 
154         ++start;
155         ++i;
156     }
157 
158     if ( i == nlen2 )
159         return true;
160 
161     return false;
162 }
163 
164 /* 2013.6.25
165  * 以上三个函数在简单模式下成立。但是还是存在错误。
166  */
167 
168 /* 2013.6.25
169  * 本次采用的是方式2,然后使用KMP来进行子串匹配。
170  * KMP算法来自博客 算法之道
171  * 网址:http://blog.csdn.net/v_july_v/article/details/7041827#comments
172  */
173 int CheckRotStrOpt( const char *s1, const char *s2)
174 {
175     int nlen1, nlen2;
176     int *overlay_value = NULL;
177     char* newS1 = NULL;
178     int index = 0;
179     int i, j, ret = false;
180 
181     if ( s1 == NULL || s1[0] == '\0'
182         || s2 == NULL || s2[0] == '\0' )
183     {
184         printf( "Error for arguments.\n" );
185         return -1;
186     }
187 
188     nlen1 = strlen( s1 );
189     nlen2 = strlen( s2 );
190 
191     newS1 = (char *) malloc( nlen1 * 2 * sizeof( char ) + 1 );
192     if ( newS1 == NULL )
193     {
194         printf( "Error for malloc!\n" );
195         return -1;
196     }
197 
198     // 拷贝字符串s1
199     strncpy( newS1, s1, nlen1 );
200     strncpy( newS1 + nlen1, s1, nlen1 );
201     nlen1 <<= 1;
202     newS1[nlen1] = '\0';
203 
204     overlay_value = (int *) malloc( nlen2 * sizeof(int) );
205     if ( overlay_value == NULL )
206     {
207         printf( "Error for malloc.\n" );
208         free( newS1 );
209         return -1;
210     }
211     overlay_value[0] = -1;
212 
213     // nextArray
214     for ( i = 1; i < nlen2; ++i )
215     {
216         index = overlay_value[i - 1];
217         while ( index >= 0 && s2[index + 1] != s2[index] )
218         {
219             index = overlay_value[index];
220         }
221 
222         if ( s2[index + 1] == s2[index] )
223             overlay_value[i] = index + 1;
224         else
225             overlay_value[i] = -1;
226     }
227 
228     i = 0, j = 0;
229     while ( i < nlen2 && j < nlen1 )
230     {
231         if ( newS1[j] == s2[i] )
232         {
233             ++i;
234             ++j;
235         }
236         else if ( i == 0 )
237         {
238             ++j;
239         }
240         else
241         {
242             i = overlay_value[i - 1] + 1;
243         }
244     }
245 
246     if ( i == nlen2 )
247         ret = true;
248 
249     free( newS1 );
250     free( overlay_value );
251 
252     return ret;
253 }
254 
255 int main()
256 {
257     char* str10 = "AABCDA";
258     char* str11 = "ABCD";
259     char* str20 = "CDAA";
260     char* str21 = "ACBD";
261     int ret = 0;
262 
263     ret = CheckRotStrOpt( str10, str20 );
264     printf( "The result is %d.\n", ret );
265 
266     ret = CheckRotStrOpt( str11, str21 );
267     printf( "The result is %d.\n", ret );
268 
269     return 0;
270 }
View Code

  

 

posted @ 2013-06-25 09:40  life91  阅读(239)  评论(0编辑  收藏  举报