转:数组循环移位

数组循环移位

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

不合题意的解法如下:

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

版本1

void RightShift(char *arr, int N, int k)
{
    while(k--)
    {
        char t = arr[N-1];
        for(int i = N-1; i > 0; i--)
            arr[i] = arr[i-1];
        arr[0] = t;
    }
}

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


分析与解法

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

【解法一】

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

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

版本2

void RightShift(char *arr, int N, int k)
{
    k %= N;
    while(k--)
    {
        char t = arr[N-1];
        for(int i = N-1; i > 0; i--)
            arr[i] = arr[i-1];
        arr[0] = t;
    }
}

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

【解法二】

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

1.   逆序排列abcdabcd1234 → dcba1234;

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

3.   全部逆序:dcba4321 → 1234abcd

版本3

Reverse(char *arr, int b, int e)
{
    for(; b < e; b++, e--)
    {
        char temp = arr[e];
        arr[e] = arr[b];
        arr[b] = temp;
    }
}

RightShift(char *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-12 14:47:08

转:数组循环移位的相关文章

编程之美2.17 数组循环移位

问题描述: 设计一个算法,把一个含有N元素的数组循环左移或者右移K位. 解决方法: 1. 暴力解法------O(KN) 2. 颠倒位置------O(N) 具体思路和代码: 1. 暴力解法------O(KN) 思路:循环K次,每次移动一位 代码: 1 //右移 2 void s1(int A[], int n, int k) 3 { 4 k = k % n; 5 for(int i = 0; i < k; i++) 6 { 7 int t = A[n-1]; 8 for(int j = n-

编程之美6:数组循环移位

楼主又来~(≧▽≦)/~啦啦啦,科研,就是要这么一鼓作气.额,其实楼主的老本行是推公式啊,做这些算法题,其实是楼主在偷懒.额,话不多说了,快请出我们今天的主角吧!还是关于数组的-数组循环移位. 下面我们来看下题目的要求. 题目要求: 设计一个算法,把一个含有N个元素的数组循环右移K位,要求时间复杂度为O(N),且只允许使用两个附加变量. 题目解答 我们来自己给个例子,来帮助自己思考.如数组为[1, 2, 3, 4, 5, 6, 7, 8],循环移位4次. 原始序列:[1, 2, 3, 4, 5,

2.17——数组循环移位

题目: 设计一个算法,将一个含有N个元素的数组循环右移K位,要求时间复杂度为O(N),只允许使用两个附加变量 思路: 如abcd1234: 逆序排列abcd:abcd1234--->dcba1234 逆序排列1234:dcba1234--->dcba4321 逆序所有       :dcba4321--->1234abcd 下面是代码: 1 #include<iostream> 2 using namespace std; 3 4 typedef int INT; 5 6 v

编程之美2.17之数组循环移位

题目描述:设计一个算法,把一个含有N个元素的数组循环右移K位,要求算法的时间复杂度位O(Log2N),且只允许使用两个附加变量. 什么意思呢,就是说如果输入序列为:abcd1234,右移2位即变为34abcd12.唯一的要求就是使用两个附加变量. 其实这道题编程珠玑上面也出现过,书中给出的一种符合题意的解法是巧妙地进行翻转.以把abcd1234右移4位为例: 第一步:翻转1234,abcd1234---->abcd4321 第二步:翻转abcd,abcd4321---->dcba4321 第三

数组循环移位问题

问题描述:把一个数组中的元素循环右移k位,时间复杂度严格为O(n),不能是O(kn). 分析:对于这个问题很容易想到的一种方法是依次循环右移,但是这样的话时间复杂度是O(kn),明显不符合题目要求,在之前的博客中,我写的对于字符串的移位问题,可以借助里面的方法三步反转法. 第一步:根据n和k求出分界点的下标,假设为index,则index=n-k(数组下标从0开始),将整个数组分为两部分,0~index-1和index~n-1, 第二步:将0~index-1部分反转. 第三布:将index~n-

2.17 数组循环移位

题目:把一个含有N个元素的字符串右移K位,要求时间复杂度为O(N),且只允许使用两个附加变量. 例子: 字符串为:abcd1234,右移4位,结果变为:1234abcd 思路: 移动前跟移动后是有两段的顺序是不变的,所以可以把这两段看成两个整体 右移K位的过程就是把数组的两部分交换一下. 交换的过程:(1)逆序排列第一部分 (2)逆序排列第二部分 (3)再全部逆序! 代码: #include <iostream> using namespace std; const int MAXN = 10

编程之美2.17—数组循环移位(旋转数组)

题目: 把一个含有N个元素的额数组循环右移K位,要求时间复杂度O(N),且只允许使用两个附加变量. 解法一:O(N^2) 每次将数组中的元素右移移位,循环K次.当K>N时,右移K位和右移K%N位是一样的. MyShift(int a[],int N,int K) { K%=N; while(K--) { int t=a[N-1]; for(int i=N-1;i>0;i--) a[i]=a[i-1]; a[0]=t; } } 解法二:O(N) 假如数组abcd1234 1.逆序abcd:abc

软件工程——结对开发环形数组

一.题目: 返回一个整数数组中最大子数组的和. 要求: 输入一个整形数组,数组里有正数也有负数. 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. 如 果数组A[0]……A[j-1]首尾相邻,允许A[i-1], …… A[n-1], A[0]……A[j-1]之和最大. 同时返回最大子数组的位置. 求所有子数组的和的最大值.要求时间复杂度为O(n). 二.设计思路 开始想的是用链表实现数组首尾相连,可是由于链表用着不太熟悉,便想了另一种算法: 当最大值未出现跨域是就按常规方法计算找

数组循环移动

数组循环移动 个人信息:就读于燕大本科软件工程专业 目前大三; 本人博客:google搜索"cqs_2012"即可; 个人爱好:酷爱数据结构和算法,希望将来从事算法工作为人民作出自己的贡献; 编程语言:C++ ; 编程坏境:Windows 7 专业版 x64; 编程工具:vs2008; 制图工具:office 2010 powerpoint; 硬件信息:7G-3 笔记本; 真言 向前走,不要犹豫,犹豫就是让别人超越自己的最好机会. 题目 数组向右循环移动. 解法 我设计的算法时间复杂度