问题描述
将一个n
元一维向量向左循环移位k
个位置。例如,n=9,k=3
, 向量abcdefghi
就变成了defghiabc
,在考虑到节省内存的情况下,如何在O(n)
的复杂度下对向量进行移位。
方法一
移动c = x[0], x[0] = x[k], x[k] = x[2*k], ...
依次类推,直到返回到x[0]
,改为从c
取值。
shift_zaji.c fist algorithm1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| int gcd(int a, int b)
{
int r;
while(1){
r = a % b;
if ( r == 0 )
return b;
a = b;
b = r;
}
}
void shift(char * str, int n, int k)
{
int turns = gcd(n, k);
int i, j, tmp;
char c;
k = k % n;
for( i= 0; i < turns; ++ i){
c = str[i];
tmp = i;
while (1){
j = tmp + k;
if ( j >= n )
j -= n;
if ( j == i )
break;
str[tmp] = str[j];
tmp = j;
}
str[tmp] = c;
}
}
|
方法二 块交换算法
对向量进行循环移位其实是交换向量ab
的两个部分,得到向量ba
,如果a
代表向量的前k
个元素,分为两种情况,
length(a) < length(b)
那么将b
分为blbr
, 其中br
与a
等长,那么将a
与br
进行交换,最后形成brbla
,现在只要交换brbl
的子问题。
length(a) >= length(b)
那么将a
分为alar
, 其中al
与b
等长,那么将al
与b
进行交换,最后形成baral
,现在只要交换aral
的子问题。
shift_block_swap.c block swap algorithm1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| void swap(char * str, int a_l, int b_l, int len)
{
int i = a_l , j = b_l, k;
for( k = 0; k < len; k ++){
str[a_l + k] ^= str[b_l + k];
str[b_l + k] ^= str[a_l + k];
str[a_l + k] ^= str[b_l + k];
}
}
void shift(char * str, int n, int k)
{
int i = k;
int p = k;
int j = n - p;
while ( i != j){
if( i > j ){
swap(str, p - i , p, j);
i -= j;
}else {
swap(str, p - i, p + j - i, i);
j = j - i;
}
}
swap(str, p - i, p, j);
}
|
方法三 求逆算法
同方法二,将问题归结为ab
转化为ba
,先对a
求逆得ar
,对b
求逆得到br
,对arbr
逆得ba
,就是所求的结果
shift_reverse.c reverse algorithm1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| void reverse(char * str, int start, int end)
{
while( start < end ){
str[start] ^= str[end];
str[end] ^= str[start];
str[start] ^= str[end];
start ++;
end --;
}
}
void shift(char * str, int n, int k)
{
k = k % n;
reverse(str, 0, k - 1);
reverse(str, k, n - 1);
reverse(str, 0, n - 1);
}
|