数组循环右移算法,只用一个临时变量

数组循环右移算法,只用一个临时变量

  • 日期: 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

时间复杂度分析

在计算最大公约数部分,算法的时间复杂度为 O ( lg ( min ( n , k ) ) ) O(\lg(\min(n,k)))
本算法只需要对每个位置的数据移动1次,在移动环节,算法的时间复杂度为 O ( n ) O(n)
整体的时间复杂度为 O ( n ) O(n)

代码演示

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)

发布了36 篇原创文章 · 获赞 23 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/still_night/article/details/84662311