文章来自:http://blog.youkuaiyun.com/v_JULY_v/archive/2011/04/14/6322882.aspx
算法一:左旋转字符串
题目描述:定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部。
如把字符串abcdef左旋转2位得到字符串cdefab。
请实现字符串左旋转的函数,要求对长度为n的字符串操作的时间复杂度为O(n),空间复杂度为O(1)。
思路一:
以下的4点文字分析,引自网友zhedahht(http://zhedahht.blog.163.com/blog/#m)。
分析:
1、如果不考虑时间和空间复杂度的限制,最简单的方法莫过于把这道题看成是把字符串分成前后两部分,通过旋转操作把这两个部分交换位置。
2、于是我们可以新开辟一块长度为n+1的辅助空间,把原字符串后半部分拷贝到新空间的前半部分,在把原字符串的前半部分拷贝到新空间的后半部分。不难看出,这种思路的时间复杂度是O(n),需要的辅助空间也是O(n)。
3、因此,我们另寻思路,咱们试着把字符串看成有两段组成的,记为XY。左旋转相当于要把字符串XY变成YX。
我们先在字符串上定义一种翻转的操作,即翻转字符串中字符的先后顺序:把X翻转后记为XT,显然有(XT)T=X。
我们首先对X和Y两段分别进行翻转操作,这样就能得到XTYT。
接着再对XTYT进行翻转操作,得到(XTYT)T=(YT)T(XT)T=YX。正好是我们期待的结果。
4、分析到这里我们再回到原来的题目:我们要做的仅仅是把字符串分成两段,
第一段为前面m个字符,其余的字符分到第二段。再定义一个翻转字符串的函数,按照前面的步骤翻转三次就行了。时间复杂度和空间复杂度都合乎要求。
- // 字符串旋转算法.cpp : Defines the entry point for the console application.
- //copyright@ yiyibupt && July
- //已测试正确,yuucyf update,2011.04.20.
- #include "stdafx.h"
- #include <cstdio>
- #include <cstring>
- void Rotate(char *pszStart, char *pszEnd)
- {
- while(pszStart != NULL && pszEnd != NULL && pszStart < pszEnd)
- {
- char cTemp = *pszStart;
- *pszStart =*pszEnd;
- *pszEnd = cTemp;
- pszStart++;
- pszEnd --;
- }
- }
- void LeftRotate(char *pszStr, int nCnt)
- {
- if(NULL == pszStr) return ;
- int nLen = strlen(pszStr);
- if(nCnt > 0 && nCnt <= nLen)
- {
- char *pxFirst = NULL, *pxEnd = NULL;
- char *pyFirst = NULL, *pyEnd = NULL;
- pxFirst = pszStr;
- pxEnd = pszStr + nCnt - 1;
- pyFirst = pszStr + nCnt;
- pyEnd = pszStr + nLen - 1;
- Rotate(pxFirst, pxEnd);
- Rotate(pyFirst ,pyEnd);
- Rotate(pszStr, pszStr + nLen - 1);
- }
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- char aszStr[] = "Modified by yuucyf";
- LeftRotate(aszStr, 8);
- printf("%s/n",aszStr);
- return 0;
- }
flyinghearts:
① 动态分配一个同样长度的数组,将数据复制到该数组并改变次序,再复制回原数组。(最最普通的方法)
② 利用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。
通过不断将数组划分,和交换,直到不能再划分为止。分组过程与求最大公约数很相似。
④ 所有序号为 (i+t*k) % n (i为指定整数,t为任意整数),会构成一个循环链(共有gcd(n,k)个,gcd为n、k的最大公约数),每个循环链上的元素只要移动一个位置即可,总共交换了n次。