编程珠玑第二章的内容,有些内容没有看明白作者的意思。下面是向量左旋和变位词的问题。
一、将一个n元向量左旋转i个位置。例如当N=8,i=3时,向量abcdefgh旋转为defghabc。
这个题目编程之美也有2.17节数组的循环移位和3.1节字符串移位包含的问题。总结下,大概有5种解法,但是编程珠玑上有两种不是很明白,简单介绍下三种算法。
第一种算法比较直接,可以写一个每次都向左移动一位,移动3次即可完成,算法复杂度为i*N。这里还有一个误区,往往会认为i<N其实,并不一定,也可能会有i>>N的情况,这个时候,可以注意到当循环移动N次后向量还原成原来的样子,所以可以先对i=i%N,这样的话i就不会很大,算法复杂度为O(N2)。
第二种算法可以利用空间换时间的方法。也是先对i处理i=i%N,然后开辟一个i大小的空间,保存字符串前i个值。然后直接对把字符串从第i位向前移动i位,然后把空间i个字符补充在后面即可。
第三种算法是通过反转,可以把字符串分为ab两个字串,对a反转~a,对b反转得到~b,ab变为~a~b然后对~a~b整体反转,即可得到ba。此算法还可以针对有些要求,例如要求对abc字符串中c串和a串调换位置,即可对a、b、c串分别进行反转然后整体反转即可。这样时间复杂度只与N有关系为O(N)。下面是三种算法的代码。
#include <iostream> using namespace std; void leftShift1(char *a, int len, int i); void leftShift2(char *a, int len, int i); void leftShift3(char *a, int len, int i); void reverse(char *a, int s, int e); int main() { char a[] = "abcdefgh"; leftShift3(a, 8, 3); printf("%s\n", a); return 0; } void leftShift1(char *a, int len, int i) { i=i%len; while(i--) { char temp = a[0]; for(int j=0; j<len; j++) a[j] = a[j+1]; a[len-1] = temp; } } void leftShift2(char *a, int len, int i) { char *temp = new char[i](); memcpy(temp, a, i); memcpy(a, &a[i], len-i); memcpy(&a[len-i], temp, i); } void leftShift3(char *a, int len, int i) { reverse(a, 0, i-1); reverse(a, i, len-1); reverse(a, 0, len-1); } void reverse(char *a, int s, int e) { while(s<e) { char temp = a[s]; a[s] = a[e]; a[e] = temp; s++; e--; } }