zoukankan      html  css  js  c++  java
  • 数组循环移位

        从本节开依据网上的一些资料学习总结常见的一些算法问题(CSDN程序员编程艺术),第一个总结的是“数组循环移位”算法。

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

      算法示例:abc1234循环左移3位abc1234->1234abc。

      最先想到的办法,每次想做移动一个位置,循环K次,算法的时间复杂度O(K*N):

    void LeftShift(char* arr, int N, int k)
    {
        while(k--)
        {
            char temp =  arr[0];
            for (int i =1;i != N;i++)
                arr[i-1] = arr[i];
            a[N-1] = temp;
        }
    }

      这种方法不满足题目要求,需要做进一步的修改。主要有两种思路:1)考虑如何一次到位,将元素正确的映射到需要移动到的位置;2)序列转折算法。

      对于第一种思路,先把数组中的元素顺时针方向的圆钟,那么向做移动k个位置,等价于将圆钟逆时针旋转K个位置。在编程的时候,关键是如何找到这种映射关系。上例中向左移动三个位置,第3个位置元素将会移动到第0个位置(arr[0] = arr[3]),第6个位置元素替换到第3个位置,第9个位置的元素(圆钟的第9个元素对应数组中第9%7=2位置元素)。以此类推完成替换。但这种方法需要特别注意的是:可能在某处循环移动中仅做小循环移动(如某种情况:0<-3<-6<-0),为此我们一旦出现小循环,我们需要强制从一个新的位置开始再次循环。思路一实现代码:

    void left_shift(char* arr, int k)
    {
        int N = strlen(arr);
        int beg_pos = 0;
        int current_pos = beg_pos;
        char temp = arr[beg_pos] ; 
        for (int i =0; i != N; i++)
        {
            int next_pos = (current_pos+k)% N;
            if (next_pos != beg_pos)
            {
                arr[current_pos] = arr[next_pos];
                current_pos = next_pos;
            }
            else
            {
                arr[current_pos] = temp;
                beg_pos++;
                temp = arr[beg_pos];
                current_pos = beg_pos;
            }
        }
    
    }
    int main()
    {
        char str[] = "abcd123";
        cout<<"Please Enter shift position:";
        int k;
        cin>>k;
        cout<<"Before shift:"<<str;
        left_shift(str, k);
        cout<<"\nAfter shift:"<<str;
        system("pause");
        return 0;
    }
        

      

      思路二实现方法则相对比较巧妙,运用了序列转置公式。我们观察之前的例子可以发现:数组由两个部分组成,arr[0:k]部分与arr(k:N-1]部分,左移k个元素实际上就是这两个部分对调了顺序。假设原序列Z=XY,由X,Y两部分组成,其中X含有k个元素,则左移k个元素等价于Z' =YX。为了得到Z',需要使用序列转置公式:

                                                

    因此算法的步骤如下:

    1) 翻转序列X。前面例子中abc->cba

    2) 翻转序列Y。前面例子1234->4321

    3) 组合翻转后序列,并做翻转。组合后的序列cba4321->1234abc。

    算法实现如下:

    void reverse(char* arr, int beg_pos, int end_pos)
    {
        for(;beg_pos < end_pos;beg_pos++, end_pos--)
        {
            char temp = arr[beg_pos];
            arr[beg_pos] = arr[end_pos];
            arr[end_pos] = temp;
        }
    }
    
    void left_shift(char* arr, int k)
    {
        int N = strlen(arr);
        reverse(arr, 0, k-1);
        reverse(arr, k, N-1);
        reverse(arr, 0, N-1);
    
    }
    
    int main()
    {
        char str[] = "abcd123";
        cout<<"Please Enter shift position:";
        int k;
        cin>>k;
        cout<<"Before shift:"<<str;
        left_shift(str, k);
        cout<<"\nAfter shift:"<<str;
        system("pause");
        return 0;
    }

      比较两者方法,思路一比较容易想到,但是里面可能隐藏着“小循环”不易察觉,需要做额外的注意,方法一正确性证明比较困难一点。方法二,相对比较优雅,但难以想到这种解决方案。

  • 相关阅读:
    3.流程控制语句
    pandas数据处理(一)pymongo数据库量大插入时去重速度慢
    windows下载安装redis
    Scrapy(一)爬知乎所有用户信息
    Mongodb去除重复的数据,pymongo去重
    selenium爬虫报错:Message: stale element reference: element is not attached to the page document 促成1分钟爬完斗鱼主播信息。
    用pyspider爬斗鱼主播信息
    曼城新闻情报站(二)Django框架的爬虫
    曼城新闻情报站(一)爬取3大网站的曼城新闻
    Beautiful Soup多线程爬取斗鱼所有主播信息(改良版)
  • 原文地址:https://www.cnblogs.com/wangbogong/p/3099208.html
Copyright © 2011-2022 走看看