旋转字符串

旋转字符串

题目描述:

给定一个字符串,要求把字符串前面的若干个字符移动到字符串的尾部,如把字符串“abcdef”前面的2个字符'a'和'b'移动到字符串的尾部,使得原字符串变成字符串“cdefab”。请写一个函数完成此功能,要求对长度为n的字符串操作的时间复杂度为 O(n),空间复杂度为 O(1)。

分析和解法:

解法一:暴力位移法

首先,我看到题目的第一个想法就是可以通过暴力一位一位的挪移来实现题目要求。
源代码如下:

#include 
#include 

using namespace std;
 
void LeftShiftOne(char* s, int n)    //完成当前字符串的第一个字符到尾部 
{
    char t = s[0];   //保存当前字符串的第一个字符 
    for (int i = 1; i < n; i++)
    {
        s[i - 1] = s[i];
    }
    s[n - 1] = t;
}

int main()
{
    char str[100];
    int m; 
    cin.getline(str,100);  //用于输入一行字符串,普通cin最多输入“ abcd”
    cin>>m;
    while(m--)
    {
        LeftShiftOne(str, strlen(str));
    }
    cout<

分析:针对长度为n的字符串来说,假设需要移动m个字符到字符串的尾部,那么总共需要 m*n 次操作,同时设立一个变量保存第一个字符,如此,时间复杂度为O(m * n),空间复杂度为O(1),空间复杂度符合题目要求,但时间复杂度不符合,所以,得需要寻找其他更好的办法来降低时间复杂度。

解法二:三步反转法

(这个方法是我从书上学到的,我一开始也没想到。。。)
将一个字符串分成X和Y两个部分,在每部分字符串上定义反转操作,如XT,即把X的所有字符反转(如,X="abc",那么XT="cba"),那么就得到下面的结论:(XTYT)^T=YX,显然就解决了字符串的反转问题。

例如,字符串 abcdef ,若要让def翻转到abc的前头,只要按照下述3个步骤操作即可:

  • 首先将原字符串分为两个部分,即X:abc,Y:def;
  • 将X反转,X->XT,即得:abc->cba;将Y反转,Y->YT,即得:def->fed。
  • 反转上述步骤得到的结果字符串XTYT,即反转字符串cbafed的两部分(cba和fed)给予反转,cbafed得到defabc,形式化表示为(XTYT)^T=YX,这就实现了整个反转。
    源代码如下:
#include 
#include 

using namespace std;
 
void MyReverse(char* s, int from, int to)   //自身反转 
{
    while(from < to)
    {
        char t = s[from];
        s[from++] = s[to];
        s[to--] = t;
    }
}

int main()
{
    char str[100];
    int n,m;
    cin.getline(str, 100);
    cin>>m;
    n = strlen(str);
    MyReverse(str, 0, m-1);
    MyReverse(str, m, n-1);
    MyReverse(str, 0, n-1);
    cout<

分析:这就是把字符串分为两个部分,先各自反转再整体反转的方法,时间复杂度为O(n),空间复杂度为O(1),达到了题目的要求。

特别注意:

  • 是旧的C 头文件,对应的是基于char*的字符串处理函数,并无类,所以不能 string s1
  • 是对应于旧C 头文件的std 版本,实际上只是在一个命名空间std中include了
  • 是包装了std 的C++头文件,对应的是新的string 类,string s1就是建立一个string类的对象
  • 汉字之所以乱码, 是因为汉字是多字节的, 如果采用单字节翻转,必然就乱码了。你需要判断汉字是几个字节(N), 然后整体翻转移动这N个字节
  • 这里我还想说明一下关于C++输入输出流的问题,有兴趣的可以看一下C/C++输入输出流总结

参考资料:《编程之法》The Art of Programming By July

你可能感兴趣的:(旋转字符串)