数组旋转的高效算法
2008-02-29 16:02
344 查看
学校网速超慢,难得有机会用自己的博客。等以后条件好点了,一定多写点心得,和大家一起交流,希望大家常来。
现在向大家介绍一个原来在论坛上碰到过的一个问题,题目很短,大致如下:
一维数组,数组长度为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个单位,怎么样,是不是很有趣阿?
现在向大家介绍一个原来在论坛上碰到过的一个问题,题目很短,大致如下:
一维数组,数组长度为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个单位,怎么样,是不是很有趣阿?
相关文章推荐
- php中通过数组进行高效随机抽取指定条记录的算法
- php中通过数组进行高效随机抽取指定条记录的算法
- 在一个整型数组中有一个元素的出现次数超过了数组长度的一半,试设计一个 在时间上尽可能高效的算法,找出这个元素。
- 【LeetCode-面试算法经典-Java实现】【033-Search in Rotated Sorted Array(在旋转数组中搜索)】
- 第 2 章 第 4 题 几种数组旋转算法效率分析
- JavaScript删除数组重复元素的5个高效算法
- 问题描述如下: 有2.5亿个整数(这2.5亿个整数存储在一个数组里面,至于数组是放在外存还是内存,没有进一步具体说明); 要求找出这2.5亿个数字里面,不重复的数字的个数; 另外,可用的内存限定为600M; 要求算法尽量高效,最优;
- 第 2 章 第 3 题 数组旋转问题 平移算法实现2
- JavaScript删除数组重复元素的5个高效算法
- 算法练习六:旋转数组的最小数字
- 一个无序整数数组,数组元素大于5个,请用一种高效的算法找出其中最大的5个值.
- 数组左旋转k位 —— C++标准算法库中最悲剧的函数:rotate
- C语言输出旋转后数组中的最小数元素的算法原理与实例
- (算法)旋转有序数组中查找某个数
- 微软算法100题69 求旋转数组中的最小元素
- 九度OJ 1386 旋转数组的最小数字 【算法】
- 重拾算法之剑指Offier——旋转数组的最小数字
- [算法学习]数组的旋转
- [剑指offer]算法6 旋转数组的最小数字
- [算法]找出旋转数组的最小数字