数组循环移位

95 篇文章 0 订阅
93 篇文章 0 订阅

数组循环移位

要求:设计一个算法,把一个含有N个元素的数组循环右移K位,要求时间复杂段为O(N),且只允许使用两个附加变量。


分析:

在翻阅《编程之美》时看到了这道题,虽然书上已经给了一个完善简便的解法,但是自己却想到了一个时间O(n)空间O(1)的算法。这里先给出书中的算法,再给出我的算法。

书中使用的是三次逆序操作。

比如要对“abcd1234”右移4位,可以:

(1)逆序abcd:“abcd1234” -> “dcba1234”

(2)逆序1234:“dcba1234” -> “dcba4321”

(3)全部逆序:“dcba4321” -> “1234abcd”


代码:

def reverse(arr, left, right):
    i = left
    while i <= ((left + right) / 2):
        arr[left], arr[right] = arr[right], arr[left]
        i += 1
        left += 1
        right -= 1


def rightShift(arr, n, k):
    k %= n
    reverse(arr, 0, n-k-1)
    reverse(arr, n-k, n-1)
    reverse(arr, 0, n-1)

另一种思路:

先循环移动k%l次,从每一轮循环仅仅移动i,i+k,i+2k等位置,使其在本轮循环结束后除初始移动的元素外,其余元素均处于最终位置。

比如对”1 2 3 4 5 6 7 8“右移动三位:

第一轮:”1 2 3 4 5 6 7 8“ -> "4 2 3 7 5 6 1 8"

第二轮:"4 2 3 7 5 6 1 8" -> "4 5 3 7 8 6 1 2"

第三轮:"4 5 3 7 8 6 1 2" -> "4 5 6 7 8 3 1 2"

最后,再将末尾的”3 1 2“进行排序。得到”4 5 6 7 8 1 2 3“。

我没能正确的实现上述算法,而且,最后的排序也使得时间复杂度大于O(n)。最后在网上搜寻,找到了这种方法的延伸版本。

延伸版本的思路是每一轮循环移动除自己本身的所有元素到最终位置。

比如对”1 2 3 4 5 6 7 8“右移动两位:

第一轮:”1 2 3 4 5 6 7 8“ -> "3 2 3 4 5 6 7 8" -> "3 2 5 4 5 6 7 8" -> "3 2 5 4 7 6 7 8" (给末尾的位置赋予初始值)-> "3 2 5 4 7 6 1 8"

第二轮:"3 2 5 4 7 6 1 8" -> "3 4 5 4 7 6 1 8" -> "3 4 5 6 7 6 1 8" -> "3 4 5 6 7 8 1 8" (交换)-> "3 4 5 6 7 8 1 2"


代码:

def leftShift3(arr, k):
    arr_l = len(arr)
    i = 0
    while i < gcd(arr_l, k):
        j = i
        tmp = arr[j]
        while True:
            arr[j] = arr[(j + k) % arr_l]
            j = (j + k) % arr_l
            if j == i:
                break
            print i, ' '.join(arr)
        arr[(j + arr_l - k) % arr_l] = tmp
        print ' '.join(arr)
        i += 1


总结:

第二种思路虽然满足题目要求,但是实现起来比第一种思路复杂很多。如果实际中会用,还是用第一种思路的解法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值