例题描述
实现一个函数,将一给定字符串str
,与给定一特定值k
,要求将字符串改变为旋转后的顺序。
示例:
- 字符串
ABCD
左旋2
次:CDAB
- 字符串
ABCD
右旋3
次:DABC
左旋
思路一
保存首字符,所有字符向前挪动一位,将首字符置于字符串尾部,循环k次
- 创建临时字符变量保存首字符,因为如若不保存的话,就会被后一位的字符覆盖。
- 创建一临时指针
cur
充当传入指针(为了不影响传入的参数),作为“搬运工”。 - 建立循环使操作多次执行,循环判定条件为:指针的下一位不指向字符串结束符
\0
,而不是指针不指向\0
。
因为我们要在cur
指针指向它本身的结束符之前,将首字符插入进去。这就要求cur
最后的指向不能是结束符,否则此时插入首字符,字符间就有了“空缺”。
- 字符的搬运逻辑很简单,简单的后字符对于前字符的赋值操作。即图中的红箭头。
- 以上为单此逻辑,左旋了
1
次,为了使用参数k
,即左旋k
次。通过大循环逐次递减完成。
最终得到的处理后的字符串:BCDA
。
代码实现
void left_rotate(char *str,int k){
while(k--){
//1. 保存首字符
char temp = *str;
char *cur = str;
while(*(cur+1)){
*cur = *(cur + 1);
cur++;
}
//2. 把首字符放在最后一个位置
*cur = temp;
}
}
思路二
左旋k次,相当于逆转前k个字符,在逆转剩余字符,再整体逆转
ABCDEF
字符串,假如要左旋3
次,相当于前三个字符串先进行逆转:CBADEF
。- 在对剩下的字符串进行逆转:
CBAFED
。 - 最终整体逆转:
DEFABC
。
代码实现
因为字符串逆序操作在下面经常使用,所以我们选择将它封装成为一个函数,多次调用。
传入函数的参数为字符指针。
void reverse(char *left,char *right){
while(left < right){
char temp = *left;
*left = *right;
*right = temp;
left++;
right--;
}
}
正式逻辑
void left_rotate2(char *str,int k){
//第一次逆转前k个字符
reverse(str,str+k-1);
//第二次逆转剩下字符
reverse(str+k,str+strlen(str)-1);
//第三次整体逆转
reverse(str,str+strlen(str)-1);
}
右旋
解题思路
右旋k次,相当于左旋(str
长度 - k)次。
- 字符串
ABCD
右旋1
次:DABC
- 相当于其左旋
3
次:DABC
- 所以如果要通过左旋函数完成右旋,需要直到字符串的长度,所以用到了
strlen
的字符串库函数,通过直接调用完成右旋逻辑。
void right_rotate(char *str,int k){
//A B C D --> 一次 D A B C 右旋一次相当于左旋3次,右旋k次,相当于左旋strlen(str) - k次
left_rotate2(str,strlen(str) - k);
}
小结
我们编写程序时一定要学会“偷懒”与联想,有可能我们之前书写的函数逻辑可以变相应用与其他函数中,这种函数间的相互调用十分常见,题目中左旋函数与右旋函数通过strlen
库函数产生了关联,这是我们多次使用总结出来的规律,所以将以往的经验融会贯通,加以联想,就可以“出一份力而受益多次”,学会“偷懒”。