zoukankan      html  css  js  c++  java
  • 【编程的程序猿艺术】学习记录2:旋转的循环移位方法左弦

    【程序猿编程艺术】学习记录2:左旋转字符串之循环移位法

    GCD算法:(辗转相除法/欧几里得算法)
    gcd是求最大公约数的算法。作为TAOCP第一个算法
    gcd算法流程:
    首先给定两个整数m,n(m大于等于n)假设小于则直接交换再处理
    ①求余数 r=m%n
    ②假如r=0,算法结束,n即为所求
    否则,又一次令m <- n, n <-r 之后循环
    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    STL中rotate算法:
    对于数组移位问题。能够採用以下方法:
    ①动态分配一个相同长的数组,将数据拷贝到该数组并改变次序。再复制回原数组
    ②利用三次反转交换,首先对序列先部分逆序,之后再对后半部分逆序。之后对整个序列所有逆序。ba = (br)^T(ar)^T = (arbr)^T
    ③分组交换—及可能是数组的前面连续几个数为所要的结果
    举例:假设a长度小于b,将ab分成a0a1b。交换a0和b,得到ba1a0,仅仅须要再交换a1和a0;假设a长度小于b,将ab分成ab0b1,交换a和b0,得到b0ab1。仅仅须要交换a和b0
    我们考虑,上面这组分组交换的思想,和我们gcd算法非常相似。


    ④全部序号为(j+i*m)%n(j表示每一个循环链起始位置,i为计数变量。m表示左旋转位数,n表示字符串的长度)这样就会构成一个循环链(gcd(n,m)个),每一个循环链上的元素仅仅要移动一个位置,就可以让整个过程交换了n次。
    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    左旋转字符串
    讨论:
    1)假设m,n互为质数的情况,(公约数仅仅有1的数叫作为质数)

    for i = 0:n-1
        k = i * m % n;
    end
    

    举例:m=3,n=4 abcd -> dabc
    ch[0]->temp,ch[3]->ch[0],ch[2]=ch[3],ch[1][2],temp->ch[1]
    k寻列为0,3,2,1 发现这个就是上面依次赋值的序列。


    2)假设m,n不是互为质数时。我们要把它分成一个个互不影响的循环环全部序号为(j + i * m) % n(j 为0 到gcd(n, m)-1 之间的某一整数。i = 0:n-1)会构成一个循环链。一共同拥有gcd(n, m)个循环链。对每一个循环链分别进行一次内循环即可了。

    void rotate(string &str, int m)
    {
        int lenOfStr = str.length();
        int numOfGroup = gcd(lenOfStr, m); //求最大公约数
        int elemInSub = lenOfStr/numOfGroup;
    
        //外循环次数j为循环链的个数
        for(int j = 0;j < numOfGroup; j++)
        {
            char tmp = str[j];
            for(int i = 0; i < elemInsub - 1; i++)
            //内循环次数i为每一个循环链上的元素的个数。n/gcd(m,n)次;
                str[(j+i*m)%lenOfStr] = str[(j+(i+1)*m)%lenOfStr];
            str[(j+i*m)%lenofStr] = temp;
        }
    }
    //改写
    void my_rotate(char *begin, char *mid, char *end)
    {
        int n = end - begin;
        int k = mid - begin;
        int d = gcd(n,k);
        int i,j;
        for(i = 0; i < d; i++)
        {
            int temp = begin[i];
            int last = i;
            //i+k为i右移k的位置,%n是当i+k>n时。从左又一次開始
            for(j = (i+k)%n; j != i; j = (j+k)%n)
            {
                begin[last] = begin[j];
                last = j;
            }
            begin[last] = temp;
        }
    }
    

    举例:
    1.好比5 个学生,,编号从0 開始。即0 1 2 3 4,老师说报数。规则是从第一个学生開始,中间隔一个学生报数。报数的学生编号肯定是0 2 4 1 3。这里就相当于i 为0。k 为2,n 为5。2.然后老师又说。编号为0 的学生出列,其它学生到在他前一个报数的学生位置上去。那么学生从0 1 2 3 4=》2 3 4 _ 1。最后老师说,编号0 到剩余空位去,得到终于排位2 3 4 0 1。此时的结果,实际上就是相当于上述程序中左移k=2 个位置了。而至于为什么让编号为0 的学生出列。实际是这句:int last = i; 由于要达到这种效果0 1 2 3 4 => 2 3 4
    0 1,那么2 3 4 必需要移到前面去。
    这里还须要进一步理解。
    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    三步翻转法:
    反转X^T X=“abc” X^T="cba" (X^TY^T)^T = YX



    參考代码:

    //三步翻转法.cpp
    char * invert(char *start, char *end)
    {
        char tmp, *ptmp = start;
        while(start != NULL && end != NULL && start < end)
        {
            tmp = *start;
            *start = *end;
            *end = tmp;
            start++;
            end--;
        }
        return ptmp;
    }
    char *left(char *s, int pos)//pos是要旋转的字符个数
    {
        int len = strlen(s);
        invert(s,s+(pos-1)); //abc -> cba
        invert(s+pos,s+(len-1)); //def -> fed
        invert(s,s+(len - 1)); //cbafed -> defabc
        return s;
    }
    

    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    《剑指offer》第五十五题(平衡二叉树)
    《剑指offer》第五十五题(二叉树的深度)
    《剑指offer》第五十四题(二叉搜索树的第k个结点)
    《剑指offer》第五十三题(数组中数值和下标相等的元素)
    《剑指offer》第五十三题(0到n-1中缺失的数字)
    《剑指offer》第五十三题(数字在排序数组中出现的次数)
    《剑指offer》第五十二题(两个链表的第一个公共结点)
    《剑指offer》第五十一题(数组中的逆序对)
    http://www.cnblogs.com/amylis_chen/archive/2010/07/15/1778217.html
    在做百度地图开发
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4722112.html
Copyright © 2011-2022 走看看