题目:
给定一个字符串S[0...N-1],要求把S的前k个字符移动到S的尾部,如把字符串“abcdef”前面的2个字符“a”、“b”移动到字符串的尾部,得到新字符串“cdefab”:即字符串循环左移k。(等价于循环右移n-k位)
算法要求:时间复杂度O(n),空间复杂度为O(1)
分析:
1)暴力位移法:每次循环左移1位,调用k次即可。
时间复杂度O(kN),空间复杂度O(1)
2)三次拷贝
拷贝1:S[0...k-1]->T[0...k-1]
拷贝2:S[k...N-1]->S[0...N-1-k(即j)] j:记录数组T应该在的位置。
拷贝3:T[0...k-1]->S[N-k(即j+1)...N-1]
代码如下(注意的地方在注释中说明):
#include <stdio.h>
int main(){
const int N=6; //字符串长度
const int K=2; //左移位数
int k=K%N;//注意:如果左移位数=8,等价于2
int j=0; //记录T的存放在S的位置
//测试数据
//注:数组大小+1,给'\0'留位置,方便打印
char S[7]="abcdef";
char T[3];
//拷贝1
for(int i=0;i<k;i++){
T[i]=S[i];
}
for(int i=0;i<k;i++){
printf("%c",T[i]);
}
printf("\n");
//拷贝2
for(int i=k;i<N;i++){
S[j]=S[i];
j++;
}
for(int i=0;i<j;i++){
printf("%c",S[i]);
}
printf("\n");
//拷贝3
for(int i=0;i<k;i++){
S[j]=T[i];
j=j+1;
//注意:这里不采用S[j++]是为了防止S越界,在这里不会报错原因是数组大小是字符串+1(保留了'\0')
}
for(int i=0;i<N;i++){
printf("%c",S[i]);
}
}
3)利用转置(X’Y’)’=YX (*重点)注:算法中注意的地方和解释说明在注释中。
例如:abcdef
X=ab X’=ba
Y=cdef Y’=fedc
(X’Y’)’=(bafedc)’=cdefab
时间复杂度O(N),空间复杂度O(1)
#include <stdio.h>
int main(){
void LeftRotateString(char* s,int n,int m);
void ReverseString(char* s,int from,int to);
char s[]="abcdef";
int n=6;
int m=2;
LeftRotateString(s,n,m);
printf("%s",s);
}
//转置
void ReverseString(char* s,int from,int to){
while(from<to){
char temp=s[from];
s[from++]=s[to];
s[to--]=temp;
}
}
//注意:n为字符串位数,m为循环左移位数
void LeftRotateString(char* s,int n,int m){
m%=n; //注意:如果左移位数=8,等价于2
ReverseString(s,0,m-1);
ReverseString(s,m,n-1);
ReverseString(s,0,n-1);
}