1. 简述
设计一个算法,把一个含有N个元素的数组循环右移K位,要求时间复杂度为O(N),且只允许使用两个附加变量。
2. 思路
其实看到题目中只允许两个附加变量应该也能想到,就是两个变量倒来倒去就行了。如果熟悉希尔排序的话,这题不是问题,希尔排序里面需要分组进行插入法排序,这里就是分组进行移位而已。
举例先说明下,假设10个元素,要移动3位,那么就是三组,第一组:A[0],A[3],A[6],A[9],第二组:A[1],A[4],A[7],第三组A[2],A[5],A[8],每组分别内部移位即可。
不过有一个问题必须注意,假设移动k为,数组长度为N,当k<=N/2时,没问题,但是当k>N/2是就不对了,当K<=N/2时,每个组都至少有两个元素,每个元素都会移动一次,而且都是向着应该移动的方向,移动指定的位数,没有问题。但是当K>N/2时,有的组会没有元素,这样的组不会移动,导致错误出现了。解决方法很简单,写两个移位函数,一个左移一个右移,比如,N=10,K=7,要求左移,可以改为N=10,K=3。进行右移即可。
3. 代码
#include <iostream>
using namespace std;
void left_shift_k(char *a, int n, int k);
void right_shift_k(char *a, int n, int k);
void left_shift_k(char *a, int n, int k) {
k = k % n;
if(k > n/2) {
right_shift_k(a, n, n-k);
return;
}
int i,j;
char tmp;
for(i=0; i<k; i++) {
tmp = a[i];
for(j=i; j+k<n; j+=k)
a[j] = a[j+k];
a[j] = tmp;
}
}
void right_shift_k(char *a, int n, int k) {
k = k % n;
if(k > n/2) {
left_shift_k(a, n, n-k);
return;
}
int i,j;
char tmp;
for(i=0; i<k; i++) {
for(j=i; j+k<n; j+=k)
;
tmp = a[j];
for(; j>i; j-=k)
a[j] = a[j-k];
a[i] = tmp;
}
}
void output(const char* a) {
for(int i=0; i<8; i++)
cout << a[i] << "";
cout << endl;
}
int main() {
char a[8] = {'a', 'b', 'c', 'd', '1', '2', '3', '4'};
cout << "数组:" << endl;
output(a);
for(int i=1; i<=8; i++) {
char b[8] = {'a', 'b', 'c', 'd', '1', '2', '3', '4'};
cout << "右移" << i << "位:\t";
right_shift_k(b, 8, i);
output(b);
}
cout << endl;
for(int i=1; i<=8; i++) {
char b[8] = {'a', 'b', 'c', 'd', '1', '2', '3', '4'};
cout << "左移" << i << "位:\t";
left_shift_k(b, 8, i);
output(b);
}
system("PAUSE");
return 0;
}
输出结果为:
4. 参考
编程之美,2.17节,数组循环移位