题目说明:
要求实现一个函数,可以左旋字符串中的K个字符;
其中:
ABCD左旋一个字符得到BCDA
ABCD左旋两个字符得到CDAB
解法一:
解题思路:
拿到一组字符串之后,我们首先设置一个临时变量,存放字符串中的第一个字符。
然后把字符串中的其余字符通过循环依次前移一位,最后再把临时变量的值赋给字符串的最后的一位。
以上是字符串的一次左旋,要左旋几次就可以通过循环重复以上过程几次就可以了。
图解如下所示:
程序源码:
#include<iostream>
#include<assert.h>
#include<stdio.h>
#include<Windows.h>
using namespace std;
void string_reverse(char* arr, int len){
assert(arr);
assert(len > 0);
char temp;
temp = arr[0];
for (int i = 0; i < len - 1; ++i){
arr[i] = arr[i + 1];
}
arr[len - 1] = temp;
}
void Print(char* arr, int len){
for (int i = 0; i < len; ++i){
cout << arr[i] << " ";
}
cout << endl;
}
void test(){
char arr[] = { 'A', 'B', 'C', 'D', '1', '2', '3', '4' };
//这里用数组来表示字符串,如果用字符串来表示字符串会产生一个错误
//char *arr = "ABCD1234";
int count = 0;
int len = 0;
len = sizeof(arr) / sizeof(arr[0]);
//len = strlen(arr);
Print(arr, len);
cout << "请输入要左旋的次数:>" << endl;
cin >> count;
count %= len;
while (count--){
string_reverse(arr, len);
}
Print(arr, len);
}
int main(){
test();
system("pause");
return 0;
}
程序运行结果:
【注意】
如果向程序中所标注的直接用字符串来表示的话,会造成以下后果:
原因:
我们先来看一个内存分配示意图:
假如现在执行以下代码:
int a,b,c,d;
a=0;
b=1;
c=2;
d=3;
则a的地址最高,d的地址最低,因为这是一个压栈的过程。
但是如果执行以下语句的话:
char arr[] = { 'A', 'B', 'C', 'D', '1', '2', '3', '4' };
内存分配如图所示:
这时我们可以发现数组内存放的数据的地址是依次增加的,也就是说开始的元素地址最小,结束的元素地址最大。这是为什么呢?
原来数组在申请内存的时候不是为他的元素一个个申请内存,而是一次性的把数组所需要的内存申请好,再依次存放数组元素。
而如果我们在代码中用的是以字符串的形式的话,就会造成问题了:
char *arr = "ABCD1234";
解法二:
解题思路:
部分逆置 + 部分逆置
整体逆置
具体思路如图所示:
程序源码:
#include<iostream>
#include<assert.h>
#include<stdio.h>
#include<Windows.h>
using namespace std;
void Print(char* arr, int len){
for (int i = 0; i < len; ++i){
cout << arr[i] << " ";
}
cout << endl;
}
//数组的逆置
void reverse(char* start, char* end){
assert(start);
assert(end);
while (start<end){
*start ^= *end;
*end ^= *start;
*start ^= *end;
start++;
end--;
}
}
void string_reverse(char* arr, int len,int count){
assert(arr);
assert(len > 0);
assert(count > 0);
cout << "逆置前半段" << endl;
reverse(arr, arr + count - 1);
Print(arr, len);
cout << "逆置后半段" << endl;
reverse(arr + count, arr + len - 1);
Print(arr, len);
cout << "整体逆置" << endl;
reverse(arr, arr + len - 1);
Print(arr, len);
}
void test(){
char arr[] = { 'A', 'B', 'C', 'D', '1', '2', '3', '4' };
int count = 0;
int len = 0;
len = sizeof(arr) / sizeof(arr[0]);
cout << "请输入要左旋的次数:>" << endl;
cin >> count;
count %= len;
string_reverse(arr, len, count);
}
int main(){
test();
system("pause");
return 0;
}
程序运行结果:
解法三:
解题思路:
首先把要逆置的字符串连接成双倍字符串;
然后从双倍字符的第count位开始(count是要逆转的K个字符),到第count + len结束(len是字符串长度);
这一段就是逆转后的字符串了;
示意图如下所示:
程序源码:
#include<iostream>
#include<assert.h>
#include<stdio.h>
#include<Windows.h>
using namespace std;
void Print(char* arr, int len){
for (int i = 0; i < len; ++i){
cout << arr[i] << " ";
}
cout << endl;
}
void string_reverse(char* arr, int len, int count){
assert(arr);
assert(len > 0);
assert(count > 0);
//设置双倍字符串
char *ptemp = (char *)malloc(len * 2 + 1);
if (NULL == ptemp)
return;
char *temp = NULL;
temp = ptemp;
strcpy(ptemp, arr);
strcat(ptemp, arr);
//在双倍字符串中拿出逆置后的字符串
strncpy(arr, temp + count, len);
free(ptemp);
}
void test(){
char *arr = "ABCD1234";
int count = 0;
int len = 0;
len = strlen(arr);
Print(arr, len);
cout << "请输入要左旋的次数:>" << endl;
cin >> count;
count %= len;
string_reverse(arr, len, count);
Print(arr, len);
}
int main(){
test();
system("pause");
return 0;
}