【程序员编程艺术】学习记录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;
}

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

时间: 2024-10-29 19:09:59

【程序员编程艺术】学习记录2:左旋转字符串之循环移位法的相关文章

【程序员编程艺术】学习记录1:左旋转字符串之指针翻转法

[程序员编程艺术]学习记录1:左旋转字符串之指针翻转法 题目:左旋转字符串 定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部,如把字符串abcdef左旋转2位得到字符串cdefab.请实现字符串左旋转的函数,要求对长度为n的字符串操作的时间复杂度为O(n),空间复杂度为O(n) 思路一.暴力移位法 //暴力移位法 void leftshiftone(char *s, int n) { char t = s[0]; for(int i = 1;i < n; i++) s[i-1]

【程序员编程艺术】学习记录3:字符串包含问题

[程序员编程艺术]学习记录3:字符串包含问题 题目: 假设这有一个各种字母组成的字符串A,和另外一个字符串B,字符串里B的字母数相对少一些.什么方法能最快的查出所有小字符串B 里的字母在大字符串A里都有? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

程序员编程技术学习笔记——左旋转字符串

程序员编程技术学习笔记--左旋转字符串 1.    题目描述 给定一个字符串,要求把字符串前面的若干个字符移动到字符串的尾部,如把字符串"abcdef"前面的2个字符'a'和'b'移动到字符串的尾部,使得原字符串变成字符串"cdefab".请写一个函数完成此功能,要求对长度为n的字符串操作的时间复杂度为 O(n),空间复杂度为 O(1). 2.    解法1:暴力左移 这个解法简单粗暴易想!你不是要以为k个字符吗,我先移动一位,然后把移动一位的函数运行k次就好啦~~

程序员编程艺术

本书来自一位很有奉献精神的大神July,希望有一天能够看到本书出版. 对作者致以最真诚的感谢! 作者博客 作者微博 本书GitHub地址 CSDN下载链接 百度云盘下载链接 本书目录: 程序员编程艺术第一~三十七章集锦.............................................1 前言........................................................................1 目录................

python代码 程序员编程艺术 1.1

<程序员编程艺术:面试和算法心得>http://taop.marchtea.com/ https://github.com/julycoding/The-Art-Of-Programming-By-July/tree/master/ebook/code/python 1.1 旋转字符串 1: def simpleShift(str, n): 2: tmpStr = str[n:] + str[:n] 3: return tmpStr 4:   5: def LeftShiftOne(str):

程序员编程技术学习笔记——字符串包含

程序员编程技术学习笔记--字符串包含 1.题目描述 给定两个分别由字母组成的字符串A和字符串B,字符串B的长度比字符串A短.请问,如何最快地判断字符串B中所有字母是否都在字符串A里?为了简单起见,我们规定输入的字符串只包含大写英文字母,请实现函数boolStringContains(string &A, string &B) 比如,如果是下面两个字符串: String 1:ABCD String 2:BAD 答案是true,即String2里的字母在String1里也都有,或者说Strin

python代码 程序员编程艺术 2.1

首先一般考虑"万能的"暴力穷举(递归.回溯).但因为穷举时间复杂度通常过高,所以需要考虑更好的方法,如分治法(通过分而治之,然后归并),以及空间换时间(如活用哈希表). 此外,选择合适的数据结构可以显著提升效率,如寻找最小的k个数中,用堆代替数组. 再有,如果题目允许排序,则可以考虑排序.比如,寻找和为定值的两个数中,先排序,然后用前后两个指针往中间扫.而如果如果已经排好序了(如杨氏矩阵查找中),则想想有无必要二分.但是,如果题目不允许排序呢?这个时候,我们可以考虑不改变数列顺序的贪心

Mac开发利器之程序员编辑器MacVim学习总结

Emacs和Vim都是程序员专用编辑器,Emacs被称为神的编辑器,Vim则是编辑器之神.至于两者到底哪个更好用,网络上两大派系至今还争论不休.不过,相比之下,Emacs更加复杂,已经不能算是一个编辑器了,有人这么说:Emacs是伪装成编辑器的操作系统.与之相反,Vim的定位很明确,就是要做一个强大的编辑器.由于笔者精力有限,决定还是选择自己认为相对简单点的Vim来学习.因此,笔者将会在本文跟大家介绍Mac下Vim的安装以及简单使用.          首先,Mac系统默认已经安装了Vim.打开

程序员编程语录

程序员编程语录 1. 一个好的程序员是那种过单行线马路都要往两边看的人.(Doug Linder) 2. 程序有问题时不要担心.如果所有东西都没问题,你就失业了.(软件工程的 Mosher 定律) 3. 程序员的麻烦在于,你无法弄清他在捣腾什么,当你最终弄明白时,也许已经晚了.(超级计算机之父 Seymour Cray) 4. 我想大部分人都知道通常一个程序员会具有的美德.当然了,有三种:懒惰,暴躁,傲慢.(Perl 语言发明者 Larry Wall) 5. 编程时要保持这种心态:就好象将来要维