(7)左旋字符串
来源:互联网 发布:电子相框 知乎 编辑:程序博客网 时间:2024/06/08 19:32
原作者:v_JULY_v:http://blog.csdn.net/v_july_v/article/details/6322882
何海涛--《剑指offer》
感谢上述作者;
我仅仅是将其一些思路重新自己实现了一遍,稍作整理,以便经常温习用。
题目描述:
字符串左旋操作:将一个字符串前面的若干个字符移动到字符串尾部;例如字符串“abcdefgi” ,左旋3位,结果为“defgiabc”;
请实现字符串左旋转的函数,要求对长度为n的字符串操作时间复杂度为O(n) , 空间复杂度为O(1);
假设字符串长度:n
左旋移位:m
思路一:蛮力移位
每一移位一位:利用temp保存字符串的第一位string[0],并将后面的字符赋值给前一位,即string[i - 1] = string[i];再将temp赋值给string[n-1];
重复操作m次:
辅助空间:temp
思路二:利用指针左旋
字符串string[0] ------string[n-1] ; 指针p1 指向string[0] , p2指向string[m] ,即 相隔m位;(n > m)
交换swap(string[p1] , string[p2]) ,然后p1++ ,p2++ ,循环操作m次;
若 n % m == 0:即 n 整除 m时:
例如"123456789" ,左旋3位--》变成“456789123” ;此时 9 % 3 == 0;最终 p1 指向9 , p2指向3;
若当(n % m != 0)时:
"12345678967" -->"45678912367"时, 尾部段落“12367” , p1指向1 , p2指向6;此时无法正常的完成全部m位左旋;
我们知道string[i] ,0 <= i <= n - 1;p1指向1时,其代表下标值为6,p2指向6,其下标值为9;9 + (m - 1) = 9 + (3 - 1) = 11 > n - 1 = 10 出界;
对于尾部段落“12367” ,我们只要将“6" ,“7”一步步左移到"123"前面即可。且移动元素个数= n - p2 = 11 - 9 = 2;
算法步骤:
1、首先让p1=string[0],p2=string[m],即让p1,p2相隔m的距离;
2、判断p2+m-1是否越界,如果没有越界转到3,否则转到4;
3、不断交换*p1与*p2,然后p1++,p2++,循环m次,然后转到2。
4、此时p2+m-1 已经越界,在此只需处理尾巴。过程如下:
4.1 通过n-p2得到p2与尾部之间元素个数r,即我们要前移的元素个数。
4.2 以下过程执行r次:
string[p2]<->string[p2-1],string[p2-1]<->string[p2-2],....,string[p1+1]<->string[p1];p1++;p2++;
其中 k = (n - m) - n % m;k为总的正常左旋移动次数;
r = n - p2 ; 越界时,处理尾巴需要移动的元素个数
p2 + m - 1 用于判断是否越界(n - 1);
思路三:递归转换法
就是说,把一个规模为N的问题化解为规模为M(M<N)的问题。
举例来说,设字符串总长度为L,左侧要旋转的部分长度为s1,那么当从左向右循环交换长度为s1的小段,直到最后,由于剩余的部分长度为s2(s2==L%s1)而不能直接交换。
该问题可以递归转化成规模为s1+s2的,方向相反(从右向左)的同一个问题。随着递归的进行,左右反复回荡,直到某一次满足条件L%s1==0而交换结束。
举个具体事例说明,如下:
1、对于字符串abc def ghi gk,
将abc右移到def ghi gk后面,此时n = 11,m = 3,m’ = n % m = 2;
abc def ghi gk -> def ghi abc gk
2、问题变成gk左移到abc前面,此时n = m’ + m = 5,m = 2,m’ = n % m 1;
abc gk -> a gk bc
3、问题变成a右移到gk后面,此时n = m’ + m = 3,m = 1,m’ = n % m = 0;
a gk bc-> gk a bc。 由于此刻,n % m = 0,满足结束条件,返回结果。
即从左至右,后从右至左,再从左至右,如此反反复复,直到满足条件,返回退出
思路四:三步翻转法
举例:“abcdefgij”,左旋3位;
(1)
我们将其分为两部分:“abc” ,“defgij”;
先对子部分翻转:“abc”-->"cba" ; “defgij”-->"jigfed";
两者结合:“cbajigfed”;再对其翻转"cbajigfed" ----->"defgijabc";
(2)
也可以先对总的字符串翻转:“abcdefgij”---->"jigfedcba"
再对子部分翻转,不过这次分割子部分时:从最右边选择m位为一部分--》“cba”,左端剩余n-m位为一部分--》"jigfed"
翻转:“jigfed”-->"defgij" ,“cba”--"abc"
最终“defgijabc"
代码实现:
#include<iostream>#include<string>using namespace std;//---------------------------------------------左旋字符串------------------------------------------------------------void leftRotateOne(char* pStr , int length);//暴力void Roate(char *pHead, char *pTail);//-----------------------------------------------方法一暴力移位------------------------------------------------------void leftRoate_Soulation1(char* pStr , int length ,int m){if(pStr == NULL || m < 0)return;while(m--){leftRotateOne(pStr , length);}}void leftRotateOne(char* pStr , int length){char temp = pStr[0];for(int i = 1; i < length; i++)pStr[i-1] = pStr[i];pStr[length - 1] = temp;}//-----------------------------------------------方法二指针翻转-----------------------------------------------------void leftRoate_Soulation2(string &pStr , int m){if(pStr.length() <= 0 || m <= 0)return;int n = pStr.length();//m >= nif(m % n <= 0)return;int p1 = 0;int p2 = m;int k = (n - m) - n%m;for(int i = 0; i < k; i++){swap(pStr[p1] , pStr[p2]);p1++;p2++;}int r = n - p2;while(r--){int i = p2;while(i > p1){swap(pStr[i] , pStr[i - 1]);i--;}p2++;p1++;}}//-----------------------------------------------方法三 递归法--------------------------------------------------------void leftRoate_Soulation3(string &pStr , int length , int m , int head , int tail , bool flag){if(length <= 0 ||head == tail || m <= 0)return;//左旋if(flag == true){int p1 = head;int p2 = head + m;int n = length;int k = (n - m) - (n%m);for(int i = 0; i < k; i++){swap(pStr[p1] , pStr[p2]);p1++;p2++;}leftRoate_Soulation3(pStr , n - k , n%m , p1 , tail , false);}else{int p1 = tail;int p2 = tail - m;int n = length;int k = (n - m) - n%m;for(int i = 0; i < k; i++){swap(pStr[p1] , pStr[p2]);p1--;p2--;}leftRoate_Soulation3(pStr , n - k , n%m , head , p1 , true);}}//------------------------------------------------方法四三步旋转法------------------------------------------------char* leftRoate_Soulation4(char* pStr, int m){ if(pStr != NULL) { int nLength = static_cast<int>(strlen(pStr)); if(nLength > 0 && m > 0 && m < nLength) { char* pFirstStart = pStr; char* pFirstEnd = pStr + m - 1; char* pSecondStart = pStr + m; char* pSecondEnd = pStr + nLength - 1; // 翻转字符串的前面n个字符 Roate(pFirstStart, pFirstEnd); // 翻转字符串的后面部分 Roate(pSecondStart, pSecondEnd); // 翻转整个字符串 Roate(pFirstStart, pSecondEnd); } } return pStr;}void Roate(char *pHead, char *pTail){ if(pHead == NULL || pTail == NULL) return; while(pHead < pTail) { char temp = *pHead; *pHead = *pTail; *pTail = temp; pHead ++, pTail --; }}
- (7)左旋字符串
- 左旋字符串
- 左旋字符串
- 左旋字符串源码
- 左旋字符串算法
- 左旋字符串
- 左旋字符串
- 左旋字符串
- 左旋字符串
- 字符串左旋
- 字符串左旋算法
- 字符串左旋
- 字符串左旋旋转
- 左旋字符串
- 字符串左旋
- 左旋字符串
- 左旋字符串
- 01左旋字符串
- ssh登录很慢,登录上去后速度正常问题的解决方法
- 好的学习网站
- boost log 在项目中的应用.
- 理财
- 初尝Bootstrap
- (7)左旋字符串
- Properties 工具类
- C语言数据类型
- PHP 5.3.1 安装包 VC9 VC6 区别是什么
- 字符串排版化输出(左边十六进制,右边是对应字符)
- 认识路由器
- 如何在Oracle中复制表结构和表数据
- context:property-placeholder
- 一 、前言