字符串循环移位一直是字符串操作的常见问题,最直观的解决方法是每次将字符串中的元素移动一位,循环k次。这个算法虽然可以实现字符串的循环移位,但是算法的时间复杂度为O(k*n),其中n为字符串的长度,k为循环移位的位数。为了降低时间复杂度,通过对移位过程的详细分析发现,可以利用中间变量tmp保存str[0, k - 1],再将str[n - k, n - 1]依次放入str[0, k - 1],最后将tmp[0, k - 1]依次放入str[k, n - 1]。
#include <cstdio>
#include <cstdlib>
#include <cstring>
/**********************************************
* 将给定的字符串str循环右移k位
**********************************************/
void LoopMove(char *str, int k)
{
int i, j;
int n = strlen(str); //字符串中字符个数
k = k % n; //移动步数小于字符个数n
//中间变量tmp保存str[0...k-1]
char *tmp = (char *)malloc(sizeof(char) * k);
for(i = 0; i < k; i++)
{
tmp[i] = str[i];
}
j = 0;
//将str[n-k...n-1]插入正确位置
while(i < n)
{
str[j++] = str[i++];
}
//将tmp[0...k-1]插入正确位置
for(i = 0; i < k; i++)
{
str[j++] = tmp[i];
}
}
int main()
{
int n;
char str[100];
scanf("%s", str);
scanf("%d", &n);
LoopMove(str, n);
printf("%s\n", str);
return 0;
}
上述算法的时间复杂度虽然是O(n),但是在空间上造成了很大的浪费(因为需要申请大小为k % n的字符数组保存中间过程)。
对于字符串s右移k位后得到的s',比较两个字符串发现:s[0, n - k - 1]与s'[k, n - 1]顺序一致,s[n - k, n - 1]与s'[0, k - 1]顺序一致。
例如s:abcdefgh循环右移3位后得到s':fghabcde。s[0, 4] = s'[3, 7],s[5, 7] = s'[0, 2]。
由此我们可以对上述方法进行改进:将字符串s分为两部分s[0, n - k - 1]和s[n - k, n - 1]。右移k位的过程就是将划分的两段分别进行逆序,再对整个字符串进行逆序。
对于abcdefgh右移3位的步骤如下:
1、逆序abcde:abcdefgh -> edcbafgh
2、逆序fgh:edcbafgh -> edcbahgf
3、全部逆序:edcbahgf -> fghabcde
同理我们可以得到循环左移k位的实现方法。而且由以上分析我们也不难写出字符串左(右)移k位的实现代码。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 反转字符串str的l~h位 */
void reverse(char *str, int l, int h)
{
char c;
while(l < h)
{
c = str[l];
str[l] = str[h];
str[h] = c;
l++; h--;
}
}
/* 循环右移k位 */
void rightreverse(char *str, int n, int k)
{
k %= n;
reverse(str, 0, n - k - 1);
reverse(str, n - k, n - 1);
reverse(str, 0, n - 1);
}
/* 循环左移k位 */
void leftreverse(char *str, int n, int k)
{
k %= n;
reverse(str, 0, k - 1);
reverse(str, k, n - 1);
reverse(str, 0, n - 1);
}
int main()
{
int k;
char str[10];
scanf("%s %d", str, &k);
rightreverse(str, strlen(str), k);
printf("right reverse: %s\n", str);
scanf("%s %d", str, &k);
leftreverse(str, strlen(str), k);
printf("left reverse: %s\n", str);
return 0;
}
上述算法时间复杂度为O(n),空间复杂为O(1)。实现在线性时间内实现移位操作的同时保证空间复杂度最低。