数组循环右移算法,只用一个临时变量
- 日期: 2018年11月24日
题目要求
Exercise (1).
已知一个长度为n 的数组和一个正整数k,并且最多只能使用一个用于交换数组元素的附加空间单元,
试设计算法得到原数组循环右移k 次的结果并分析算法的时间复杂度。
实现思想
设置初始位置分别为0,1,2…d-1(d为n,k的最大公约数)
以初始位置开始,循环右移k位,到末尾继续从开头开始循环。
代码实现(Python)
def maxDiv(a:int,b:int)->int:
"""求a,b最大公约数
使用辗转相除法"""
a,b=max(a,b),min(a,b)
while a%b!=0:
a,b=b,a%b
return b
def rightMove(A:list,k:int,isPrint=False)->list:
"""将列表A循环右移k位,只用一个额外变量
参数:
A: 待移位的列表,其数量为n
k: 移动的位数
ifPrint: 是否打印移位的过程
返回:
A: 待移位的原列表
"""
#设定是否打印输出结果
if not isPrint:
def pr(*args,**kwargs):
pass
else:
pr=print
n=len(A)
pr("*"*20)
pr("{n}个数,循环右移{k}位".format(**locals()))
pr("原数组A:{A}".format(**locals()))
k=k%n # 对k取余处理,使其小于n
for s in range(maxDiv(n,k)): # 循环,次数为n,k的最大公约数
# 初始位置依次为 0,1,2,...,maxDiv(n,k)-1
p=s # 将当前位置设置为初始移动的位置
temp=A[s] # 把初始位置元素的赋值给temp
pr("temp=[{s}]".format(**locals()))
while True:
pk=(p-k)%n # 待移动的元素为向前数k个元素
if pk==s: # 如果移动到初始位置,则结束循环
break
pr("[{pk}]->[{p}]".format(**locals()))
A[p]=A[pk] # 将待移动元素移动到当前位置
p=pk # 设置当前位置,前移k位
A[p]=temp # 最后将temp的值赋值给p位置,p位置是初始位置右移k位的位置
pr("[{p}]=temp".format(**locals()))
pr("移动后A:{A}".format(**locals()))
return A
时间复杂度分析
在计算最大公约数部分,算法的时间复杂度为
本算法只需要对每个位置的数据移动1次,在移动环节,算法的时间复杂度为
整体的时间复杂度为
代码演示
n=12,k=3时
rightMove(list(range(12)),3,True)
print("\n时间测试")
%timeit rightMove(list(range(12)),3)
********************
12个数,循环右移3位
原数组A:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
temp=[0]
[9]->[0]
[6]->[9]
[3]->[6]
[3]=temp
temp=[1]
[10]->[1]
[7]->[10]
[4]->[7]
[4]=temp
temp=[2]
[11]->[2]
[8]->[11]
[5]->[8]
[5]=temp
移动后A:[9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8]
时间测试
19.2 µs ± 268 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
n=12,k=9时
rightMove(list(range(12)),9,True)
print("\n时间测试")
%timeit rightMove(list(range(12)),9)
********************
12个数,循环右移9位
原数组A:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
temp=[0]
[3]->[0]
[6]->[3]
[9]->[6]
[9]=temp
temp=[1]
[4]->[1]
[7]->[4]
[10]->[7]
[10]=temp
temp=[2]
[5]->[2]
[8]->[5]
[11]->[8]
[11]=temp
移动后A:[3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2]
时间测试
19.6 µs ± 450 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
n=12,k=7时
rightMove(list(range(12)),7,True)
print("\n时间测试")
%timeit rightMove(list(range(12)),7)
********************
12个数,循环右移7位
原数组A:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
temp=[0]
[5]->[0]
[10]->[5]
[3]->[10]
[8]->[3]
[1]->[8]
[6]->[1]
[11]->[6]
[4]->[11]
[9]->[4]
[2]->[9]
[7]->[2]
[7]=temp
移动后A:[5, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4]
时间测试
18.7 µs ± 497 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
n=100000,k=2
print("\n时间测试")
A=list(range(100000))
%timeit rightMove(A,2)
时间测试
112 ms ± 3.75 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
n=100000,k=99999
print("\n时间测试")
A=list(range(100000))
%timeit rightMove(A,99999)
时间测试
128 ms ± 18.2 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
- 欢迎评论以及发邮件和作者交流心得。
- 版权声明:本文为 m2kar 的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
- 作者: m2kar
- 打赏链接: 欢迎打赏m2kar,您的打赏是我创作的重要源泉
- 邮箱: m2kar.cn#gmail.com
- 主页: m2kar.cn
- Github: github.com/m2kar
- CSDN: M2kar的专栏