题目内容介绍(左旋转运算符)
实现一个函数,可以左旋字符串中的k个字符。
ABCD左旋一个字符得到BCDA
ABCD左旋两个字符得到CDAB
思路一:临时数组法1
-
数组arr数组中的内容要向前移动k位,前k位移到arr数组的末端。
-
首先创建一个和原数组arr等长的临时数组temp。
-
把arr数组中前k个元素赋值到temp数组的后k位。
-
然后将arr数组的前k位移到temp数组的前k位。这样旋转后的元素顺序就在temp数组中呈现。
-
再把temp数组中的整体内容赋值到原数组arr中。
相关图解
代码实现
#include <stdio.h>
#include <string.h>
#include <assert.h>
void rotate(char* arr, int len, int k)
{
assert(arr != NULL); //数组长度不能为空
assert(k <= len); //传过来的k必须小于数组长度
char temp[5] = { 0 };
int i = 0;
//将arr数组中的 前k位,移到临时数组的 后k位
for (i = 0; i < k; i++)
{
temp[len - k + i] = arr[i];
}
//将arr数组中的 后k位,移到临时数组的 前k位
for (i = k; i < len; i++)
{
temp[i - k] = arr[i];
}
//将temp数组中的内容,搬到arr数组中
for (i = 0; i < len; i++)
{
arr[i] = temp[i];
}
}
int main()
{
//先把arr中前k个字符,赋值到temp中的后面,然后将arr中k的后几位,移到temp的前几位
char arr[] = "ABCD";
int len = strlen(arr);
int k = 0;
scanf("%d", &k); //向前移动的位数
rotate(arr, len, k);
printf("%s", arr);
return 0;
}
思路二:临时数组法2
-
建立一个临时数组
-
把arr数组中的前k位(含k位)先转移到数组中去。
-
arr数组的前k位(含k位)位置此时已经空缺,把arr数组中的后k位,向前移动k位
-
然后再把临时数组中的内容附到arr数组的后面
相关图解:
代码实现:
#include <stdio.h>
#include <string.h>
#include <assert.h>
void rotate(char* arr, int len, int k)
{
assert(arr != NULL); //传入的数组不能为空
assert(k <= len); //传入的旋转数必须小于等于字符长度
char temp[5] = { 0 }; //建立一个临时数组,
int i = 0;
//用临时数组,存 前k个 arr数组中的元素
for (i = 0; i < len; i++)
{
temp[i] = arr[i];
}
//然后把arr剩下数组中的元素,向前移动k位
for (i = k; i < len; i++)
{
arr[i - k] = arr[i];
}
//把临时数组中的数字 插入到arr数组中
for (i = len - k ; i < len; i++)
{
arr[i] = temp[i - (len - k)];
}
}
int main()
{
char arr[] = "ABCD";
int len = strlen(arr); //计算字符串长度
int k = 0;
scanf("%d", &k); //向做先转k个字符
rotate(arr, len,k);
printf("%s", arr);
return 0;
}
思路三:临时变量循环法
- 上面的两种算法都有着相同的缺陷,那就是要建立一个临时数组,而且还要限定临时数组的长度,这样就严重影响了算法的灵活性,还提高了空间复杂度,
- 下面是第三种算法,它降低了空间复杂度
- 依次从arr数组中提取前k个元素,每次提取一个
- 提取的过程中,把后k个元素向前移动
- 把提取到的元素,依次添加到arr数组之后
相关图解:
代码实现:
#include <stdio.h>
#include <string.h>
#include <assert.h>
void rotate(char* arr, int len, int k)
{
assert(arr != NULL);
assert(k <= len);
int i = 0;
for (i = 0; i < k; i++)
{
char temp = arr[0];
int j = 0;
for (j = 0; j < len-1; j++)
{
arr[j] = arr[j + 1];
}
arr[len - 1] = temp;
}
}
int main()
{
char arr[] = "ABCDE";
int k = 0;
scanf("%d", &k);//要移动的位数
int len = strlen(arr);
rotate(arr, len, k);
printf("%s", arr);
return 0;
}
思路四:块变换(求逆)
- 前两种算法是提高了空间复杂度 但降低了时间复杂度
- 第三种算法是提高了时间复杂度 但降低了空间复杂度
- 到底有被有一种空间和时间复杂度相对较低的算法呢,那肯定是有滴!
- 第一步:将前k个字符两两进行翻转。
- 第二步:将后k(含k)个字符进行翻转。
- 第三步:将字符整体进行翻转。
相关图解:
代码实现:
```c
#include <stdio.h>
#include <string.h>
#include <assert.h>
void reverse(char* left,char* right)
{
while (left < right)
{
char temp = 0;
temp = *left;
*left = *right;
*right = temp;
left++;
right--;
}
}
void rotate(char* arr, int len, int k)
{
assert(arr != NULL); //传来的字符串数组不能为空
assert(k <= len); //传来的移动位数,必须小于字符串长度
//旋转前k个元素
reverse(arr, arr + k - 1);
//旋转后k(含k)个元素
reverse(arr + k , arr + len - 1);
//旋转整体元素
reverse(arr, arr + len - 1);
}
int main()
{
char arr[] = "ABCD";
int k = 0;
scanf("%d", &k);//字符向左旋转k位
int len = strlen(arr); //字符长度
rotate(arr, len, k);
printf("%s", arr);
return 0;
}