



免费预览已结束,剩余1页可下载查看
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
要求:设计一个算法,把一个含有N个元素的数组循环右移K位,要求时间复杂度为O(N),且只允许使用两个附加变量。不合题意的解法如下:我们先试验简单的办法,可以每次将数组中的元素右移一位,循环K次。abcd12344abcd12334abcd12234abcd11234abcd。版本1voidRightShift(char*arr,intN,intk)while(k-)chart=arrN-1;for(inti=N-1;i0;i-)arri=arri-1;arr0=t;虽然这个算法可以实现数组的循环右移,但是算法复杂度为O(K*N),不符合题目的要求,需要继续往下探索。分析与解法假如数组为abcd1234,循环右移4位的话,我们希望到达的状态是1234abcd。不妨设K是一个非负的整数,当K为负整数的时候,右移K位,相当于左移(-K)位。左移和右移在本质上是一样的。【解法一】大家开始可能会有这样的潜在假设,KN,右移K-N之后的数组序列跟右移K位的结果是一样的。进而可得出一条通用的规律:右移K位之后的情形,跟右移K=K%N位之后的情形一样。版本2voidRightShift(char*arr,intN,intk)k%=N;while(k-)chart=arrN-1;for(inti=N-1;i0;i-)arri=arri-1;arr0=t;可见,增加考虑循环右移的特点之后,算法复杂度降为O(N),这跟K无关,与题目的要求又接近了一步。但时间复杂度还不够低,接下来让我们继续挖掘循环右移前后,数组之间的关联。【解法二】假设原数组序列为abcd1234,要求变换成的数组序列为1234abcd,即循环右移了4位。比较之后,不难看出,其中有两段的顺序是不变的:1234和abcd,可把这两段看成两个整体。右移K位的过程就是把数组的两部分交换一下。变换的过程通过以下步骤完成:1. 逆序排列abcd:abcd1234 dcba1234;2. 逆序排列1234:dcba1234 dcba4321;3. 全部逆序:dcba4321 1234abcd。版本3Reverse(char*arr,intb,inte)for(;be;b+,e-)chartemp=arre;arre=arrb;arrb=temp;RightShift(char*arr,intN,intk)k%=N;Reverse(arr,0,N-k-1);Reverse(arr,N-k,N-1);Reverse(arr,0,N-1);编程之美中的题目要求只使用两个附加变量。王晓东编著的算法设计与实验题解中要求只用到O(1)的辅助空间。其它地方两本书的要求相同,都是O(n)的时间复杂度。两本书中的解法总结起来就是三种方法:(1)循环换位算法(2)三次反转算法(3)排列循环算法。这三种算法在王晓东的著作中都有实现代码。第一种算法是最原始的算法。第二种算法比较巧妙,即使用VU=reverse(reverse(U)reserve(V),写成数学形式就是:。于是使用三次反转也可实现。第三种方法与数学有较大关系,以下着重解释第三种方法,借此复习一下数学。对于第三种方法,王晓东老师在著作中介绍了一条循环置换分解定理:对于给定数组A0.N-1向后循环换位N-K位运算,可分解为恰好gcd(K,N-K)个循环置换,且0,.,gcd(K,N-K)-1中的每个数恰属于一个循环置换。其中gcd(x,y)表示x和y的最大公因数。我们从头开始分析这个问题,对于数组A0.n-1,要将其向后循环移动k位元素。因为每个元素右移n位后又回到了原来的位置上,所以右移k位等于右移k mod n位。考虑每个元素右移k位后的最终位置,比如对于A0,右移k位后在k mod n位置上,原来在k mod n位置上的元素右移k位后到了2*k mod n的位置上,把如此因为A0的移动而受到连环影响必须移动的位置列出来,就是下面这样一个位置序列:0,k,2*k,.,(t-1)k。其中每一项都是在模n的意义下的位置。t*k mod n 的结果是0。t是使得t*k mod n的结果为0的最小正整数。这个位置序列实质上是模n加法群中由元素k生成的一个循环子群。由群论中的结论(该结论的证明见最后)知,循环子群(k)的周期为n / gcd(k,n),元数为n / gcd(k,n),其陪集个数为gcd(k,n)。换句话说,A0.n-1循环右移k位的结果是循环子群(k)以及它的所有陪集循环右移一位。例如,将A0.5 = 1,2,3,4,5,6循环右移4位,这里n = 6, k = 4, gcd(k, n) = 2。A0的最终位置是4,A4的最终位置是2,A2的最终位置是0,这样,位置0,4,2便是由k=4生成的循环群,周期为6 / gcd(4,6) = 6 / 2 = 3,这样的循环子群共有gcd(4,6) = 2个。第三种方法的完整代码如下:/ 数组的循环移位#include int gcd(int m, int n)int r;while(r = m % n)m = n; n = r;return n;/ 因为左移的代码比右移的代码好实现的多,而右移k位/ 等价于左移-k位,-k = n - k。以下代码是通过左移-k位来实现右移k位void shiftArray(int A, int n, int k)k = n - (k % n);for(int i = 0, cnt = gcd(n, k); i cnt; i+)int t = Ai, p = i, j = (k+i) % n;while(j != i)Ap = Aj; p = j; j = (k + p) % n;Ap = t;void printArray(int A, int n)for(int i = 0; i n; i+)printf(%-3d, Ai);if(i+1)%10 = 0)printf(n);int main()int A = 1,2,3,4,5,6, 7;shiftArray(A, 7, 4);printArray(A, 7);return 0;上述所用到的那个群论结论的证明:结论:设G是一个循环群,其中一个生成元素
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 合浦食品安全培训课件
- 消防安全检查标准与操作
- 中学数学几何模块专项训练题汇编
- 小学科学三年级下册复习知识点
- 智能家居项目实施方案及风险分析
- 个性化课程表模板设计方案
- 口腔医院数字化营销体系构建
- 尽职调查流程清单及实际操作指南
- 医院安全培训个人总结课件
- 黑匣子数据讲解
- 2025年计算机二级WPS考试题目
- 护理危急值报告制度
- 运输行业特殊作业安全管理制度
- 品管圈PDCA案例-中医医院减少住院患者艾灸烫伤率医院改善成果汇报
- 《土地变更调查讲义》课件
- 财务整账合同模板
- 2020年水利水电工程标准施工招标文件
- 《农产品安全与质量检测》课件-3.2.食品中的灰分的测定
- 钢结构厂房排水系统安装方案
- 对新员工保密基本培训
- 口耳目手足课件
评论
0/150
提交评论