关于旋转字符串和回文
这个断断续续看了好长时间。
书中给了三种旋转字符串的方法
1.juggling
这个方法比较巧妙。
过程就是:假设x[] = “abcdefgh" 长度为8 从第3位开始。 即 n=8 ,i=3
执行下列交换
x[0]与x[0+i%n]
x[0+i%n]与 x[0+2*i%n] ……
每次都要模n.
一直到 再回到 x[0]为止。 即k*i%n==0的时候
注意:
如果没有完成全部交换,第二次就从x[1]开始 然后是, x[1+i],x[1+2i]......
还是要模n.
整个过程进行 i和n 的最大公约数次 就可以完成字符串的旋转。 (why? 此处没想通)
这个问题,我至今没有想明白。。。。。
不知道 ,我把整个过程说清楚没有。。 我个人觉得原书上也没有说太清楚,可能自己英文水平还不够吧,自己琢磨好久才写代码来。
没看明白,即看代码吧。看过代码就清楚了。
自己实现的代码如下:
1 void juggling (int i,int n,char *x)
2 {
3 int cycles=gcd(i,n);//最大公约数
4 int t;
5 for(int j=0;j<cycles;j++)
6 {
7 t=x[j];
8 int k=j;
9 do
10 {
11 x[k%n]=x[(k+i)%n];
12 k+=i;
13 }while(k%n!=j);
14 x[(k-i)%n]=t;
15 }
16 }
对比作者给出的代码如下:
1 void jugglerot(int rotdist, int n)
2 { int cycles, i, j, k, t;
3 cycles = gcd(rotdist, n);
4 for (i = 0; i < cycles; i++) {
5 /* move i-th values of blocks */
6 t = x[i];
7 j = i;
8 for (;;) {
9 k = j + rotdist;
10 if (k >= n)
11 k -= n;
12 if (k == i)
13 break;
14 x[j] = x[k];
15 j = k;
16 }
17 x[j] = t;
18 }
19 }
20
21 void jugglerot2(int rotdist, int n)
22 { int cycles, i, j, k, t;
23 cycles = gcd(rotdist, n);
24 for (i = 0; i < cycles; i++) {
25 /* move i-th values of blocks */
26 t = x[i];
27 j = i;
28 for (;;) {
29 /* Replace with mod below
30 k = j + rotdist;
31 if (k >= n)
32 k -= n;
33 */
34 k = (j + rotdist) % n;
35 if (k == i)
36 break;
37 x[j] = x[k];
38 j = k;
39 }
40 x[j] = t;
41 }
42 }
2.块交换
这个方法的过程就是:
让 ab ==> ba
先 a1a2b (a1=b) ==> ba2a1
然后想办法 a2a1 ==> a1a2 明显递归进行就可以了。
这个方法本来想自己写出递归的程序。
然后是怎么也没写出来,不知道怎么控制条件
分析作者给出的代码。
在某位网友的指点下,终于弄明白怎么回事情了。
1 void gcdrot(int rotdist, int n)
2 { int i, j, p;
3 if (rotdist == 0 || rotdist == n)
4 return;
5 i = p = rotdist;
6 j = n - p;
7 while (i != j) {
8 /* invariant:
9 x[0 ..p-i ] is in final position
10 x[p-i..p-1 ] = a (to be swapped with b)
11 x[p ..p+j-1] = b (to be swapped with a)
12 x[p+j..n-1 ] in final position
13 */
14 if (i > j) {
15 swap(p-i, p, j);
16 i -= j;
17 } else {
18 swap(p-i, p+j-i, i);
19 j -= i;
20 }
21 }
22 swap(p-i, p, i);
23 }
24 /*这段代码里面。 i 和 j 始终代表 每次旋转 左边 和右边 字符串长度。 例如 abc|de i=3 j=2。 然后p 初始值为i 的初始值。
25 是为了 swap的时候定位。 最后,i 和 j 只能是 1 和 1 */
26
27 交换的代码如下:
28 void swap(int i, int j, int k) /* swap x[i..i+k-1] with x[j..j+k-1] */
29 { int t;
30 while (k-- > 0) {
31 t = x[i]; x[i] = x[j]; x[j] = t;
32 i++;
33 j++;
34 }
35
36 }
37 /*交换的时候也可以用 a=a+b;b=a-b;a=a-b的原理去做,效率更高*/
开始看。。完全不知道 i j p 是什么意思。。
但还是没有把它改成 递归的形式。。 功力还是不够啊。。
3.reverse
这个方法就比前面的 简单明了多了。。
原理就是: ab ==> ba
1 arb
2 arbr
3 (arbr)r
这样就行了。
void reverse(int i,int j)
{
int t;
for(;i<j;)
{
t=x[i];x[i]=x[j];x[j]=t;
i++;
j--;
}
}
void swap(int i,int n)
{
reverse(0,i-1);//cbadefgh
reverse(i,n-1);//cbahgfed
reverse(0,n-1);//defghabc
}
简洁,明了。
还有一个思想就是回文。
快速找出回文词。
思路就是:
每个单词 打乱原来的顺序
按照字母顺序重排 作为原来的sign
这样,只要是回文,就有同样的sign。
根据相同的sign 输出回文 就行了。
stop tops pots 都有相同的sign "opst"
今天就到此吧。
读这种书真的很费劲。
坚持!