与字符串相关的问题在各大互联网公司的笔试和面试中出现的频率非常高。常见且典型的字符串问题有:“字符串的旋转”、“字符串的包含”、“字符串的全排列”、“字符串转换成整数”、“回文判断”、“最长回文子串”等。本篇介绍字符串旋转的算法。
字符串的旋转
题目描述:
给定一个字符串,要求将字符串前面的若干个字符移到字符串的尾部。例如:
将字符串“abcdefg”的前3个字符'a'、'b'、'c'移到字符串的尾部,变成了“defgabc”。
如何用代码实现这个功能呢?
第一种解法:蛮力法
看到题目描述,首先会想到将需要移动的字符一个一个地移到字符串的尾部。所以我们可以编写一个函数leftShiftOne(char * arr, int n),完成将一个字符移到字符串尾部的功能;然后多次调用该功能。
代码实现如下:
#include <stdio.h>
#include <stdlib.h>
//向左循环移动一位
void leftShiftOne(char * arr, int n)
{
//保留第一个字符
char t=arr[0];
for(int i=1 ;i<n ;i++)
{
arr[i-1]=arr[i];
}
//把t保存在数组最后的位置
arr[n-1]=t;
}
//向左循环移动m位
void leftRotateString (char * arr,int n,int m)
{
while(m--)
{
leftShiftOne(arr,n);
}
}
int main(int argc, char** argv)
{
int n;
scanf("%d",&n);
char arr[n]; //动态分配字符数组
scanf("%s",arr);
printf("旋转前:%s\n",arr);
leftRotateString(arr,n-1,3); //数组长度为n,只能存n-1个字符;每次固定移动3字符
printf("旋转后:%s\n",arr);
return 0;
}
算法复杂度分析:
时间复杂度为:O(mn),执行效率低,有待改进。
空间复杂度为:O(1)
第二种解法:三步反转
第二种思路是把需要移动的部分 和 不需要移动的部分分开,分成2部分;然后将这两个部分的字符串分别反转,最后再对整个字符串进行反转。
代码实现如下:
#include <stdio.h>
#include <stdlib.h>
//从坐标从from到to的部分反转
void reverseString(char *arr,int from,int to)
{
while(from<to)
{
char t=arr[from];
arr[from++]=arr[to];
arr[to--]=t;
}
}
void leftRotateString(char *arr,int n,int m)
{
reverseString(arr,0,m-1);//0到m-1,前面部分反转
reverseString(arr,m,n-1);//m到n-1,后面部分反转
reverseString(arr,0,n-1);//0到n-1,整体反转
}
int main(int argc, char** argv)
{
int n;
scanf("%d",&n);
char arr[n]; //动态分配字符数组
scanf("%s",arr);
printf("旋转前:%s\n",arr);
leftRotateString(arr,n-1,3); //数组长度为n,只能存n-1个字符;每次固定移动3位
printf("旋转后:%s\n",arr);
return 0;
}
算法复杂度分析:
时间复杂度为:O(n) ,时间效率大幅提高。
空间复杂度为:O(1)