数组左旋转k次的代码逻辑问题求助:我的实现存在什么错误?
问题分析与修正
你的代码核心问题出在位置映射逻辑错误,以及交换方式不符合左旋转的元素移动规则,我们一步步拆解:
1. 位置映射公式完全错误
你提到“k=1时a[0]应映射到a[n-1]”,这个理解是对的(左旋转1次,第一个元素移到末尾),但你写的(i+n-1+k)%n完全不符合这个逻辑:
- 当k=1,n=5,i=0时,计算得
(0+5-1+1)%5 = 5%5=0,相当于交换a[0]和它自己,根本没移动元素; - 当k=2,i=0时,
(0+5-1+2)%5=6%5=1,交换a[0]和a[1],这和左旋转需要把a[0]移到索引3的目标完全不符。
左旋转k次的正确位置映射应该是:
- 原数组中索引为
i的元素,左旋转k次后,应该出现在新数组的(i - k) % n位置(或者反过来,新数组索引j对应的原数组元素是(j + k) % n)。
比如原数组[1,2,3,4,5],k=2: - 原i=0的元素1,目标位置是
(0-2)%5=3; - 原i=1的元素2,目标位置是
(1-2)%5=4; - 原i=2的元素3,目标位置是
(2-2)%5=0,这完全符合预期结果[3,4,5,1,2]。
2. 逐个交换的逻辑会打乱元素
就算位置映射对了,你现在的循环方式(遍历每个i,交换a[i]和目标位置元素)也会出错:因为当你交换i和目标位置的元素后,后续循环到目标位置时,会把已经归位的元素又交换回去,最终结果完全混乱。
修正方案
这里给你两种常用的正确实现方式:
方式一:使用临时数组(直观易懂)
直接根据正确的映射关系构建新数组,代码简洁清晰:
def array_left_rotation(a, n, k): # 先处理k大于n的情况,避免无效旋转 k = k % n # 新数组的前n-k个元素是原数组的k到n-1部分,后k个是原数组的0到k-1部分 return a[k:] + a[:k]
比如输入[1,2,3,4,5],n=5,k=2,a[2:]是[3,4,5],a[:2]是[1,2],拼接后就是[3,4,5,1,2],完美符合需求。
方式二:原地修改(三次反转法,空间复杂度O(1))
如果要求不能使用额外数组,可以用经典的三次反转技巧,不需要额外空间:
- 反转数组的前k个元素;
- 反转数组的后n-k个元素;
- 反转整个数组。
代码实现:
def array_left_rotation(a, n, k): k = k % n # 处理k大于n的情况 def reverse(arr, start, end): while start < end: arr[start], arr[end] = arr[end], arr[start] start += 1 end -= 1 reverse(a, 0, k-1) reverse(a, k, n-1) reverse(a, 0, n-1) return a
测试输入[1,2,3,4,5],k=2:
- 第一步反转前2个元素:
[2,1,3,4,5] - 第二步反转后3个元素:
[2,1,5,4,3] - 第三步反转整个数组:
[3,4,5,1,2],得到正确结果。
进阶:原地循环交换(逻辑稍复杂)
如果想用原地交换的方式,需要找到元素的循环链(比如原位置0→3→1→4→2→0,这样一个循环链),然后在每个链内交换元素,而不是逐个遍历交换:
def array_left_rotation(a, n, k): k = k % n count = 0 for start in range(n): if count >= n: break current = start prev_val = a[start] while True: next_idx = (current - k) % n if next_idx == start: a[current] = prev_val count += 1 break a[current], prev_val = prev_val, a[next_idx] current = next_idx count += 1 return a
这种方式能正确处理原地交换,但逻辑相对复杂,不如前两种直观。
内容的提问来源于stack exchange,提问作者mourinho
相关产品推荐
相关产品推荐

