(转)数组循环右移

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

不合题意的解法如下:

我们先试验简单的办法,可以每次将数组中的元素右移一位,循环K次。abcd1234→4abcd123→34abcd12→234abcd1→1234abcd。伪代码如下:

代码清单2-33

RightShift(int* arr, int N, int K)

{

while(K--)

{

int t = arr[N - 1];

for(int i = N - 1; i > 0; i --)

arr[i] = arr[i - 1];

arr[0] = t;

}

}

虽然这个算法可以实现数组的循环右移,但是算法复杂度为O(K * N),不符合题目的要求,需要继续往下探索。

分析与解法

假如数组为abcd1234,循环右移4位的话,我们希望到达的状态是1234abcd。不妨设K是一个非负的整数,当K为负整数的时候,右移K位,相当于左移(-K)位。左移和右移在本质上是一样的。

【解法一】

大家开始可能会有这样的潜在假设,K<N。事实上,很多时候也的确是这样的。但严格地说,我们不能用这样的“惯性思维”来思考问题。尤其在编程的时候,全面地考虑问题是很重要的,K可能是一个远大于N的整数,在这个时候,上面的解法是需要改进的。

仔细观察循环右移的特点,不难发现:每个元素右移N位后都会回到自己的位置上。因此,如果K > N,右移K-N之后的数组序列跟右移K位的结果是一样的。进而可得出一条通用的规律:右移K位之后的情形,跟右移K’= K % N位之后的情形一样。

代码清单2-34

RightShift(int* arr, int N, int K)

{

K %= N;

while(K--)

{

int t = arr[N - 1];

for(int i = N - 1; i > 0; i --)

arr[i] = arr[i - 1];

arr[0] = t;

}

}

可见,增加考虑循环右移的特点之后,算法复杂度降为O(N),这跟K无关,与题目的要求又接近了一步。但时间复杂度还不够低,接下来让我们继续挖掘循环右移前后,数组之间的关联。

【解法二】

假设原数组序列为abcd1234,要求变换成的数组序列为1234abcd,即循环右移了4位。比较之后,不难看出,其中有两段的顺序是不变的:1234和abcd,可把这两段看成两个整体。右移K位的过程就是把数组的两部分交换一下。变换的过程通过以下步骤完成:

1.   逆序排列abcd:abcd1234 → dcba1234;

2.   逆序排列1234:dcba1234 → dcba4321;

3.   全部逆序:dcba4321 → 1234abcd。

伪代码可以参考如下:

代码清单2-35

Reverse(int* arr, int b, int e)

{

for(; b < e; b++, e--)

{

int temp = arr[e];

arr[e] = arr[b];

arr[b] = temp;

}

}

RightShift(int* arr, int N, int k)

{

K %= N;

Reverse(arr, 0, N – K - 1);

Reverse(arr, N - K, N - 1);

Reverse(arr, 0, N - 1);

}

这样,我们就可以在线性时间内实现右移操作了。

时间: 2024-10-31 07:27:35

(转)数组循环右移的相关文章

线性表(一)&mdash;&mdash;数组循环右移算法

源码:rshift.cpp #include "stdafx.h" #include <stdio.h> /************************************************************************/ /* 数组循环右移算法 */ /************************************************************************/ /* * 要求:只用一个元素大小的辅助空间

数组循环右移

Q:把一个含有 N 个元素的数组循环右移 K 位,要求时间复杂度为 O (N),且只允许使用两个附加变量. 开始的思路: 1.若k=整数倍N, 完成:k大于N,k=N%k:k小于N,开始处理. 2.tmp1保存取出的元素a[k]:a[0]放在k:tmp2保存a[2k], tmp1放入2k:tmp1保存a[3k],tmp2放入3k...直到位置[0]被放入一个新值,一轮循环完毕.这是一个从位置[0]出发,又回到位置[0]的接龙游戏. 仔细考虑下,发现,若N%k==0,则需要从[0]开始,[0]结束

数组循环右移问题

首先,假设我们有一个具有6个元素的数组: 1,2,3,4,5,6 现在我们要对这个数组循环右移4次,我们很直接很够推出它的结果是:3,4,5,6,1,2 .但是我们如何去实现这样一个问题呢? 我觉得大家最容易想到的方法就是: step1:保存好数组中最后一个元素的值 step2:从第一个元素到倒数第二个元素依次向右移动一个位置 step3:然后将刚保存的值放到空出来的数组第一个位置 虽然这个方法想起来很简单,但是它的效率却不是很高,它的时间复杂度是O(n^2). 现在,我再介绍一种效率较高的算法

习题8-3 数组循环右移(20 分)

本题要求实现一个对数组进行循环右移的简单函数:一个数组a中存有n(>0)个整数,将每个整数循环向右移m(≥0)个位置,即将a中的数据由(a?0??a?1???a?n?1??)变换为(a?n?m???a?n?1??a?0??a?1???a?n?m?1??)(最后m个数循环移至最前面的m个位置). 函数接口定义: int ArrayShift( int a[], int n, int m ); 其中a[]是用户传入的数组:n是数组的大小:m是右移的位数.函数ArrayShift须将循环右移后的数组仍

PAT 1008(数组循环右移问题)

1008 数组元素循环右移问题 (20分) 一个数组A中存有N(>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(≥0)个位置,即将A中的数据由(A?0??A?1???A?N−1??)变换为(A?N−M???A?N−1??A?0??A?1???A?N−M−1??)(最后M个数循环移至最前面的M个位置).如果需要考虑程序移动数据的次数尽量少,要如何设计移动的方法? 输入格式: 每个输入包含一个测试用例,第1行输入N(1≤N≤100)和M(≥0):第2行输入N个整数,之间用空格分隔

【算法编程】循环右移一个数组

仅用一个辅助节点将一个大小为n数组循环右移k位的三种办法: 1.时间复杂度最大:将所有元素每次只移动一位,总共移动k次,程序实现十分容易,在此就不具体实现了. 2.时间复杂度适中:依次将每个元素都放到辅助节点上,然后将其储存到目的节点,具体程序如下: #include<iostream> using namespace std; int gcd(int x,int y); int main() { int n,k; cout<<"请输入数组的维数"<<

1008. 数组元素循环右移问题 (20)

1008. 数组元素循环右移问题 (20) 一个数组A中存有N(N>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(M>=0)个位置,即将A中的数据由(A0 A1--AN-1)变换为(AN-M -- AN-1 A0 A1--AN-M-1)(最后M个数循环移至最前面的M个位置).如果需要考虑程序移动数据的次数尽量少,要如何设计移动的方法? 输入格式:每个输入包含一个测试用例,第1行输入N ( 1<=N<=100).M(M>=0):第2行输入N个整数,之间用空格

数组的循环右移问题(好未来笔试题)

问题描述:给定一个整数数组,长度为n,现在要求该数组循环右以m个元素. 例如,数组为{1,2,3,4,5,6,7,8,9},循环右移3个元素后为变成{7,8,9,1,2,3,4,5,6} 分析:这是我曾经参加好未来笔试时的一道编程题目,考完试后,总结了以下几种解法,给大家分享下. 解法一:辅助空间法,思路很简单,就是另外开辟一块和原来数组一样大小的空间.然后先把原来数组的最后面的m个元素复制到 新数组的前面,然后再把原来数组的前面的元素复制到新数组的后面,最后再把新数组的全部元素复制到原来的数组

数组元素循环右移及静态链表

1. 静态链表 https://github.com/BodhiXing/Data_Structure/tree/master/StaticListDemo 2. 数组元素循环右移 https://pta.patest.cn/pta/test/17/exam/4/question/262 思路:不做循环,只是换方式打印输出. 1 #include <stdio.h> 2 #include <math.h> 3 4 5 int main() { 6 int n,m,i; 7 scan