- 使用语言
C语言
- 题目描述
实现一个函数,可以左旋字符串中的k个字符。
例如:ABCD左旋一个字符得到BCDA
ABCD左旋两个字符得到CDAB
- 思路解析+代码实现(多思路)
思路一:
常规思路很简单,很容易想出来,以左旋一个字符为例,创建一个变量tmp将字符串的第一个字符赋给tmp,然后将字符串所有的字符往前移一位比如移动之前是ABCD,移动之后就是BCDD,因为最后一个字符是没有后一个字符前移覆盖它的,所以保持不变,然后再将tmp赋给最后一个字符即完成一个字符的左旋。若需要左旋n个字符就再套一个循环,反复完成左旋一个字符的操作就行了。不过需要注意的是,假如字符串的长度是len,如果需要左旋的字符数量大于字符串长度了就会进行很多无用的操作,所以加上一个语句n %= len(n是需要左旋的字符个数,len是字符串长度)。
这个思路的时间复杂度是O(N^2),下面看代码实现:
#include<stdio.h>
#include<string.h>
#include <stdlib.h>
#include<assert.h>
void leftmove(char str[],int n,int sz)
{
int i = 0;
assert(str);
n %= sz;
while(n--)
{
char tmp = str[0];
for(i=0; i<sz-1; i++)
{
str[i] = str[i+1];
}
str[sz-1] = tmp;
}
}
int main()
{
int n = 0;
char str[] = "ABCD";
int len = strlen(str);
printf("请输入要旋转几个字符:>");
scanf("%d",&n);
leftmove(str,n,len);
printf("%s\n",str);
return 0;
}
思路二:
将这个思路稍微优化一下,左旋n个字符就是将左旋一个字符重复n遍,这样做效率有点低,我们可以再创建一个字符数组temp用来存需要左旋的字符,再将原字符串的所以字符往前移动2位,例如ABCD,移动后就是CDCD,然后将temp[]里的字符依次赋给原字符串的最后2位即可,虽然循环数量更多了,但是这样不用循环套循环,时间复杂度是O(N)
#include<stdio.h>
#include<string.h>
#include <stdlib.h>
#include<assert.h>
void leftmove(char arr[], int n, int len)
{
assert(arr);
int i = 0;
char temp[] = "";
n %= len;
for (i = 0; i < n; i++)
{
temp[i] = arr[i];
}
for (i = 0; i < len - n; i++)
{
arr[i] = arr[i + n];
}
for (i = 0; i < n; i++)
{
arr[i + len - n-1] = temp[i];
}
}
int main()
{
int n = 0;
char str[] = "ABCD";
int len = strlen(str);
printf("请输入要旋转几个字符:>");
scanf("%d",&n);
leftmove(arr, n, len);
printf("%s", arr);
return 0;
}
思路三:
这种思路很难一开始就想到,时间复杂度是O(N),相比上面的两种思路会好很多。
代码实现
#include<stdio.h>
#include<string.h>
#include <stdlib.h>
#include<assert.h>
void Reverse(char *start, char *end)
{
while (start < end){
*start ^= *end;
*end ^= *start;
*start ^= *end;
start++, end--;
}
}
void leftmove(char *str, int len, int num)
{
assert(str);
assert(len > 0);
assert(num > 0);
num %= len;
char *mid = str + num - 1;
Reverse(str, mid);
Reverse(mid + 1, str + len - 1);
Reverse(str, str + len - 1);
}
int main()
{
int n = 0;
char str[] = "ABCD";
int len = strlen(str);
printf("请输入要旋转几个字符:>");
scanf("%d",&n);
leftmove(arr, n, len);
printf("%s", arr);
return 0;
}
思路四:
上面的三种思路已经将时间复杂度逐渐优化到了O(N),但是还能继续优化,理论上可以达到时间复杂度O(1)。思路如下:
代码实现:
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
void leftmove(char *str, int len, int num)
{
assert(str);
assert(len > 0);
assert(num > 0);
num %= len;
char *buf = (char*)malloc(2 * len + 1);
strcpy(buf, str);
strcat(buf, str);
strncpy(str, buf+num, len);
free(buf);
buf = NULL;
}
int main()
{
int n = 0;
char str[] = "ABCD";
int len = strlen(str);
printf("请输入要旋转几个字符:>");
scanf("%d",&n);
leftmove(arr, n, len);
printf("%s", arr);
return 0;
}
四种思路中前两种算是常规思路,容易想上去的,后两种一时半会很难想到,我个人建议使用第三种思路,而且这种思路在别的题目依旧可以用到。