您的位置:首页 > 编程语言

数组循环移位

2015-09-22 10:51 204 查看
数组循环移位

要求:设计一个算法,把一个含有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

总结:

第二种思路虽然满足题目要求,但是实现起来比第一种思路复杂很多。如果实际中会用,还是用第一种思路的解法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  编程之美 算法