学校网速超慢,难得有机会用自己的博客。等以后条件好点了,一定多写点心得,和大家一起交流,希望大家常来。
现在向大家介绍一个原来在论坛上碰到过的一个问题,题目很短,大致如下:
一维数组,数组长度为N,求将数组循环右移M个长度的算法。要求:
1 时间复杂度为O(N)
2 空间复杂度为O(1)
下面给出我的解决方案:
#include <iostream>
using namespace std; 
void RightMove(int a[],int length,int moveSize) 
...{ 
/**//*
本算法采用跳跃移动的方式。例如:
a[4] = {1,2,3,4}循环右移2位,先从下标startPos = 3 开始 将a[3]保存到temp中
,移动下一个位置a[1]到a[3]中
然后startPos-- 从 startPos = 2 开始 将a[2]保存到temp中。。。。
简单地说,就是从一个初始位置开始,移动一组数据,这组数据都在最终的位置。
*/ 
//本算法时间为O(n),空间为O(1); 
int count = 0;
int startPos,nextPos,curPos,endPos;
// startPos 开始移动的位置,初值为N-1
//nextPos 下一个要移动的位置
//curPos 当前移动的位置
//endPos 结束的位置
int temp; 
moveSize %= length; 
startPos = length - 1;
endPos = startPos - moveSize;
while (count < length && startPos > endPos) 
...{
curPos = startPos;
nextPos = (startPos - moveSize + length) % length;
temp = a[startPos]; 
while(nextPos!=startPos) 
...{
a[curPos] = a[nextPos];
curPos = nextPos;
nextPos = (curPos - moveSize + length) % length;
count++;
}
if (curPos != startPos) 
...{
a[curPos] = temp;
count++;
} 
startPos--;
}
} 
void DisPlayArray(int a[],int size) 
...{
for (int i = 0; i < size; i++)
cout < < a[i] < < endl;
} 
int main() 
...{ 
int a[9] = ...{1,2,3,4,5,6,7,8,9}; 
RightMove(a,9,4);
DisPlayArray(a,9); 
return 0;
}
另外,还有一个比较经典的方法。虽然效率比上面的要低点,但其思想的确很精辟!因为它的算法很简单,
假设数组长度为len+1,循环右移m位。可以分以下3个步骤来解决:
1)Reverse( a[], 0, len-m )
2)Reverse( a[], len-m+1, len )
3)Reverse( a[], 0, len )
Reverse( a[], i, j ) 完成的就是数组下标从 i 到 j 的这个序列的 转置
举各例子,a[5] = {1,2,3,4,5}; m = 2
Reverse( a, 0, 2 ) 序列 = {3, 2, 1, 4, 5 }
Reverse( a, 3, 4) 序列 = {3,2,1,5,4 }
Reverse( a, 0, 4) 序列 = {4,5,1,2,3}
数组的确是循环右移了2个单位,怎么样,是不是很有趣阿?
7605

被折叠的 条评论
为什么被折叠?



