344.反转字符串
一、做题感受&第一想法
思路清晰,前后双指针,成功ac。
双指针:前指针向后,后指针向前,直到二者相遇,在过程中将两指针指向的元素swap。
void reverseString(char* s, int sSize) {
int i = 0, j = sSize - 1;
char t;
while(i<=j){
t = s[i];
s[i] = s[j];
s[j] = t;
i++;
j--;
}
return;
}
二、学习文章后收获
1.swap()函数的两种实现方式
方式一:最传统的用一个temp作为桥梁,暂存中间值。
方式二:异或运算的性质
①a^a=0 ②a^0=0
//交换a、b
a ^= b;
b ^= a;
a ^= b;
说明:该方法有一个极其易错的点:a和b的值可以相同,但是a和b不能是“同一个东西”(否则a变的时候b也变了,会在第二条语句处得到0^0=0,最后两个值全为0了!!!)
举例:
在本题中,如果写成:(注意while循环条件带了等于号!)
void reverseString(char* s, int sSize) {
int i = 0, j = sSize - 1;
char t;
while(i<=j){ //注意此处!
s[i] ^= s[j];
s[j] ^= s[i];
s[i] ^= s[j];
i++;
j--;
}
return;
}
那么当i==j时,s[i]和s[j]实际上是同一个东西!最后会把这个位置的元素变成0,也就是char型的\0
。所以出错。
while条件改成while(i<j)
则不出错。
541. 反转字符串II
一、做题感受&第一想法
承接上题,有思路,但是被各种下标绕晕了……写出来了但是废了很多时间debug。
二、学习文章后收获
三、过程中遇到的问题
1.C语言中逻辑运算符使用规范
不能连用!连不等式要拆开写!
错误示范:if( 0 < a < b ){...}
正确写法:if( a > 0 && a < b){...}
卡码网:54.替换数字
一、做题感受&第一想法
思路比较清晰:新开辟字符串空间用于记录更改后的字符串。但是一开始只申请了指针,没有申请空间,于是报错(笑丝)。
#include<stdio.h>
#include<malloc.h>
int main(){
char* rawStr = (char*)malloc(sizeof(char)*10001); //用于保存原字符串
scanf("%s",rawStr);
char* returnStr = (char*)malloc(sizeof(char)*60001); //申请新空间用于记录更改后的字符串
char numStr[7] = "number";
int cnt = 0, i = 0, t = 0;
for(i = 0; rawStr[i]!='\0';i++){
if(rawStr[i] >= 'a' && rawStr[i] <= 'z'){ //字母:保留
returnStr[cnt] = rawStr[i];
cnt++;
}
else{ //非字母:改成number
for(t = 0;t < 6;t++){
returnStr[cnt] = numStr[t];
cnt++;
}
}
}
returnStr[cnt] = '\0';
printf("%s",returnStr);
free(returnStr);
return 0;
}
二、学习文章后收获(待完成)
因为暂未学习c++,所以暂时跳过。
三、过程中遇到的问题
1.一定要分清楚指针和申请空间
一开始只申请了指针,没有申请空间,于是报错(笑丝)。
报错代码:
char* rawStr;
scanf("%s",rawStr);
151.翻转字符串里的单词
一、做题感受&第一想法
暴力解法,从后往前遍历字符串,每遍历到一个单词则记录下单词的上下边界,复制到returnStr中,并加上空格。
但是:空间复杂度高。
#define MAXSIZE 100000
int mySwap(char* s, int low, int high, char* returnStr, int j){
for(;high>=low;low++){
returnStr[j] = s[low];
j++;
}
returnStr[j] = ' ';
j++;
return j;
}
char* reverseWords(char* s) {
char* returnStr = (char*) malloc(sizeof(char)*MAXSIZE);
int i = 0, j = 0, length = 0, temp = 0;
for(i = 0; s[i] != '\0'; i++){
length++;
}
printf("%d\n",length);
for(i = length-1; i >= 0; i--){
if(s[i] != ' '){
temp = i;
while( i >= 0 && s[i] != ' '){ //必须要加上i>=0啊啊啊,而且不能放后面,否则报错。
i--;
}
j = mySwap(s,i+1,temp,returnStr,j);
}
}
j--;
returnStr[j] = '\0';
return returnStr;
}
二、学习文章后收获
1.如何用O(1)空间复杂度解题?
①全部翻转字符串
②将每个单词逐个翻转
③双指针法去除空格
2.代码
void reverse(char* s, int low, int high){ //将字符串s的low~high下标元素翻转。
while(low < high){
s[low] ^= s[high];
s[high] ^= s[low];
s[low] ^= s[high];
low++;
high--;
}
return;
}
char* reverseWords(char* s) {
int length = 0;
for(int i = 0; s[i] != '\0'; i++){
length++;
}
//【1.翻转整个字符串】
reverse(s,0,length-1);
//【2.翻转字符串里的每个单词】
int low = 0, high = 0;
for(int i = 0; i<length;i++){
if(s[i] != ' '){
low = i;
while(i < length && s[i] != ' '){ //别忘了i<length的判断条件!
i++;
}
high = i-1;
reverse(s,low,high);
}
}
//【3.双指针法,去除多余空格】
int fast = 0, slow = 0;
for(fast = 0;fast < length;fast++){
if(s[fast] != ' '){
while(fast < length && s[fast] != ' '){ //别忘了fast < length的判断条件!
s[slow] = s[fast];
slow++;
fast++;
}
s[slow] = ' ';
slow++;
}
}
slow--;
s[slow] = '\0';
return s;
}
3.数组中移除元素:双指针法
4.删除空格的另一个逻辑
如果当前字符是空格,并且下一个字符也是空格,则跳过
否则,将当前字符复制到新字符串的 slow 位置
void removeExtraSpace(char* s) {
int start = 0; // 指向字符串开头的指针
int end = strlen(s) - 1; // 指向字符串结尾的指针
while (s[start] == ' ') start++; // 移动指针 start,直到找到第一个非空格字符
while (s[end] == ' ') end--; // 移动指针 end,直到找到第一个非空格字符
int slow = 0; // 指向新字符串的下一个写入位置的指针
for (int i = start; i <= end; i++) { // 遍历整个字符串
if (s[i] == ' ' && s[i+1] == ' ') { // 如果当前字符是空格,并且下一个字符也是空格,则跳过
continue;
}
s[slow] = s[i]; // 否则,将当前字符复制到新字符串的 slow 位置
slow++; // 将 slow 指针向后移动
}
s[slow] = '\0'; // 在新字符串的末尾添加一个空字符
}
三、过程中遇到的问题
1.老问题:&&运算符前后生效次序问题
以下代码的判断条件不能互换位置,否则报数组越界错。
while( i >= 0 && s[i] != ' '){ //必须要加上i>=0啊啊啊,而且不能放后面!!否则报错。
i--;
}
2.循环中不要忘记边界条件的判断
for(fast = 0;fast < length;fast++){
if(s[fast] != ' '){
while(fast < length && s[fast] != ' '){ //别忘了fast < length的判断条件!
s[slow] = s[fast];
slow++;
fast++;
}
s[slow] = ' ';
slow++;
}
}
卡码网:55.右旋转字符串
一、做题感受&第一想法
其实这题相当于”翻转字符串里的单词“的无空格版本!
①翻转整个字符串
②翻转前k个字符
③翻转后面的其他字符
#include <stdio.h>
#include <malloc.h>
#define MAXSIZE 10000
void reverse(char* s, int low, int high){
while(low<high){
s[low] ^= s[high];
s[high] ^= s[low];
s[low] ^= s[high];
low++;
high--;
}
return;
}
int main(){
int k = 0;
char s[MAXSIZE];
scanf("%d\n",&k);
scanf("%s",s);
int length = 0, i = 0;
for( i = 0; s[i] != '\0'; i++){
length++;
}
reverse(s,0,length-1); //翻转整个字符串
reverse(s,0,k-1); //翻转前k个字符
reverse(s,k,length-1); //翻转后面的其他字符
printf("%s",s);
return 0;
}
二、学习文章后收获
1.其实先局部翻转,再整体翻转也可以。
2.左旋右旋其实一样,只要看清楚翻转区间即可!