前提:我的问题不是Cyclic rotation in Python的重复。我不是在问如何解决问题,或者为什么我的解决方案不起作用,我已经解决了它并且起作用了。我的问题是关于发现相同问题的另一种特殊解决方案,因为我想了解另一种解决方案背后的逻辑。
我遇到了以下循环数组旋转问题(在源代码下面):
给出由N个整数组成的数组A。旋转数组意味着将每个元素右移一个索引,并将数组的最后一个元素移到第一位。例如,数组A = [3、8、9、7、6]的旋转为[6、3、8、9、7](元素右移一个索引,而6移到第一位)。 目标是将阵列旋转K次;也就是说,A的每个元素将向右移K次。
我设法通过以下Python代码解决了该问题:
def solution(A , K):
N = len(A)
if N < 1 or N == K:
return A
K = K % N
for x in range(K):
tmp = A[N - 1]
for i in range(N - 1, 0, -1):
A[i] = A[i - 1]
A[0] = tmp
return A
然后,在以下网站https://www.martinkysel.com/codility-cyclicrotation-solution/上,我找到了以下解决同一问题的方法:
def reverse(arr, i, j):
for idx in xrange((j - i + 1) / 2):
arr[i+idx], arr[j-idx] = arr[j-idx], arr[i+idx]
def solution(A, K):
l = len(A)
if l == 0:
return []
K = K%l
reverse(A, l - K, l -1)
reverse(A, 0, l - K -1)
reverse(A, 0, l - 1)
return A
有人可以向我解释这个特定解决方案的工作原理吗? (作者未在其网站上解释它)
我的解决方案在大型A
和K
(例如K < N
,例如:
A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] * 1000
K = 1000
expectedResult = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] * 1000
res = solution(A, K) # 1455.05908203125 ms = almost 1.4 seconds
由于K < N
,我的代码的时间复杂度为O(N * K)
,其中N是数组的长度。
对于大K
和小N
(K > N
),我的解决方案表现出色,这要归功于模运算K = K % N
:
A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
K = 999999999999999999999999
expectedRes = [2, 3, 4, 5, 6, 7, 8, 9, 10, 1]
res = solution(A, K) # 0.0048828125 ms, because K is torn down to 9 thanks to K = K % N
另一方面,即使在N > K
且复杂度为O(N)
的情况下,另一种解决方案在所有情况下都表现出色。
该解决方案背后的逻辑是什么?
感谢您的关注。
答案 0 :(得分:3)
首先让我谈谈K < N
的基本情况,这种情况下的想法是将数组分为两部分A
和B
,A
是第一个NK个元素数组和B
个最后K个元素。该算法分别反转A
和B
,最后反转整个数组(两部分分别反转)。要处理K > N
的情况,请考虑每次N次反转数组就再次获得原始数组,因此我们可以使用模块运算符查找拆分数组的位置(仅反转真正有用的时间,以避免没用的移位)。
图形示例
一个图形化的分步示例可以帮助您更好地理解该概念。请注意
K = 3
); 开始于:
看起来,我们想要在最终输出前面的是倒数的最后3个字母,现在让我们将其倒置到位(算法的第一个倒数):
现在反转前N-K个元素(算法的第二个反转):
我们已经有了解决方案,但是在相反的方向上,我们可以通过反转整个数组来解决它(算法的倒数第三次):
这是最终输出,原始数组以K = 3循环旋转。
代码示例
让我们从pythonp开始,再给出一个逐步的示例,
A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
K = 22
N = len(A)
我们找到分裂指数:
K = K%N
#2
因为在这种情况下,前20个移位将无用,所以现在我们反转原始数组的最后K(2)个元素:
reverse(A, N-K, N-1)
# [1, 2, 3, 4, 5, 6, 7, 8, 10, 9]
如您所见9和10发生了移位,现在我们反转前N-K个元素:
reverse(A, 0, N-K-1)
# [8, 7, 6, 5, 4, 3, 2, 1, 10, 9]
最后,我们反转整个数组:
reverse(A, 0, N-1)
# [9, 10, 1, 2, 3, 4, 5, 6, 7, 8]
请注意,反转数组的时间复杂度为O(N)。