中国大学MOOC-陈越、何钦铭-数据结构-起步能力自测题
自测-3 数组元素循环右移问题 (20分)
一个数组A中存有N(>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(M≥0)个位置,即将A中的数据由(A0 A1.. A{N-1})变换为(A{N-M} ... A{N-1} A0 A1 ... A{N-M-1} )(最后M个数循环移至最前面的M个位置)。如果需要考虑程序移动数据的次数尽量少,要如何设计移动的方法?
输入格式:
每个输入包含一个测试用例,第1行输入N(1≤N≤100)和M(M≥0);第2行输入N个整数,之间用空格分隔。
输出格式:
在一行中输出循环右移MM位以后的整数序列,之间用空格分隔,序列结尾不能有多余空格。
问题分析:
要实现移动次数尽量少,所以我们可以思考一下最少需要移动几次。最少应该是N次(M不为0时)。如果我们假设N个整数中存在一个没有移动,那么这个元素之前的第M个元素需要移动到这个位置,那么这个元素如果没有移动,它的值将被覆盖,换句话说这个数组将永远失去一个元素,显然这种情况是不被允许的。所以每个元素都需要至少移动一次。
Case 1 我们首先观察一个例子,数组(1, 2, 3, 4, 5, 6, 7)向右移动2个位置,那么1需要到3,3需要到5,5需要到7,7需要到2,2需要到4,4需要到6,6需要到1,如此移动7次,我们实现了循环移动的过程,而且仅仅移动了7次。是不是所有的数组都可以通过这样的方式实现移动呢?答案是不一定。
Case 2 我们再来观察一个例子数组(1, 2, 3, 4, 5, 6)向右移动2个位置,那么1需要到3,3需要到5,5需要到1。那么接下来呢?我们如果不选择作出一些改变的话,我们将进入这个1,3,5的循环里,而这显然不是我们需要的,所以再回到1之后,我们需要调整到2,然后开始新的循环移动,这样就可以完成2,4,6的位置改变。
这时候需要思考,究竟什么情况下Case 1会发生,而什么时候case 2会发生呢?
假设我们最最开始移动的元素下标为a0,数组长度为L,移动距离为M (讨论中M<L, 因为M=L时数组发生没有任何改变,而M>L总可以划归到M<L的情况里) ,已经发生了第k次移动,那么很容易得到第k次移动时,需要被移动的元素的下标为:
ak = (a0 + M* k) % L. 而如果ak等于a0,那么case 2就会发生,如果ak始终不等于a0,那么我们一直处于case 1中。
更具体一点:
case 1:(M* k) % L != 0
case 2 :(M* k) % L == 0
在完成了以上分析后,我们得到代码实现如下:(python 3, 已通过PTA平台全部测试案例)
# This code is designed to adjust given array/list
# by shifting every element by M units rightwards
# circularly
# e.g. a= [1, 2, 3, 4, 5, 6] M=2 -->
# this input set will give out [5, 6, 1, 2, 3, 4]
# sample input :
# 6 2 (length of array, shift distance)
# 1 2 3 4 5 6 (elements of array)
############## input processing #################
InputInfo_1 = input("")
InputInfo_2 = input("")
InputList_1 = InputInfo_1.split(' ', 1)
array_len = int( InputList_1[0] ) #get the length of array
shift_dist = int ( InputList_1[1] ) #shift distance rightwards
InputList_2 = InputInfo_2.split(' ', array_len-1 )
originalArray = [0] * array_len #initiate a list with all 0s
for k in range(array_len) :
originalArray[k] = int( InputList_2[k] ) # Transfer string var to int var
shift_dist = shift_dist % array_len
pre_repository = originalArray[0]
this_index = ( 0 + shift_dist ) % array_len
for m in range(array_len) :
if (shift_dist * (m+1) ) % array_len != 0 :
post_repository = originalArray[this_index]
else:
post_repository = originalArray[ (this_index +1 ) % array_len]
originalArray[this_index] = pre_repository
if (shift_dist * (m+1) ) % array_len != 0 :
pre_repository = post_repository
this_index = ( this_index + shift_dist ) % array_len
else:
pre_repository = originalArray[ (this_index +1 ) % array_len]
this_index = ( this_index + shift_dist + 1 ) % array_len
for n in range(array_len - 1):
print(originalArray[n], end =' ')
print(originalArray[-1])