hello,大家好,本文为大家带来字符串的常见操作以及常见算法题讲解,话不多说,开讲吧!
提取字符串里的数字
此题为经典的字符串操作,读取用户输入的字符串,要求分离出字符串中的数字并输出,具体代码如下:
void getNumsInStr(char *str){
if(str == NULL) return;
int nums[100];
int i = 0, count = 0;
int begin = 0, end = 0;
if(str[0] == '0'){ // 首字符为0的特殊处理
nums[count++] = 0;
i = 1;
}
while(1){
// 跳过无效字符
while(str[i] && (str[i] < '0' || str[i] > '9')) i++;
if(str[i] >= '0' && str[i] <= '9'){
nums[count] = str[i] - '0';
// 双指针求解字符串中的数字
begin = i, end = i + 1;
while(str[end] >= '0' && str[end] <= '9'){
nums[count] = nums[count] * 10 + str[end] - '0';
end ++;
}
// 更新索引值为end
i = end;
// 更新数字数量
count ++;
}else{
break;
}
}
printf("输入字符串中的数字有:\n");
for(i = 0; i < count; ++i){
printf("%d\t", nums[i]);
}
printf("%n");
return ;
}
复制
上述程序的运行结果如下:
需要注意的是,本代码存在一个小BUG,也即输入字符串为"0000"时,输出应该为"0 0 0 0"而不是"0 0";欢迎读者讨论并提出修改意见。
无重复字符的最长子串
此题输入为一个字符串,要求输出无重复字符的最长子串,需要注意的是子串是连续的,子序列则是不连续的。
思路分析:定义一个数组用于统计每个字符的出现次数,采用双指针算法,当快指针对应的字符出现次数大于1时,慢指针前移缩小区间,直到慢指针对应的字符次数为1;定义一个变量保留最长的区间长度即可,C语言代码如下:
void longestSubString(char *str){
if(str == NULL) return ;
int count[128] = { 0 }; // 利用数组构建哈希表
int fast = 0, slow = 0, ret = 0;
for(fast = 0; str[fast] != '\0'; fast++){
// 当str[fast]对应的字符数大于1时,slow指针前移,缩小区间
if(++ count[str[fast] > 1){
while(slow < fast){
count[str[slow ++]] --;
if(count[str[slow]] == 1) break;
}
}
// 更新结果
ret = ret > (fast - slow + 1) ? ret : (fast - slow + 1);
}
printf("%s的无重复字符最长子串长度为%d\n", str, ret);
return ;
}
复制
上述代码的运行结果如下:
最长回文子串
此题为输入为一串字符串,要求输出此字符串的最长回文子串,可采用中心扩散法,定义三个指针,一个指针left向左扩散,一个指针right向右扩散,另外一个中心指针进行遍历,由于回文串可能是奇数串(asdsa),也可能是偶数串(qwwq);因此需要分两种情况进行讨论,C语言代码如下:
char *longestPalindrome(char *str){
int len = strlen(str);
if(len == 0 || len == 1) return str;
int maxLen = 1, start = 0;
int left = 0, right = 0;
for(int i = 0; i < len; ++i){
// 偶数串
left = i, right = i + 1;
// 指针中心扩散,求解回文串
while(left >= 0 && right < len && str[left--] == str[right++]);
// 更新结果
if(right - left - 1 > maxLen){
maxLen = right - left - 1;
start = i + 1;
}
// 奇数串
left = i - 1, right = i + 1;
// 中心扩散求解回文串长度
while(left >= 0 && right < len && str[left--] == str[right++]);
if(right - left - 1 > maxLen){
maxLen = right - left - 1;
start = i + 1;
}
}
char *res = (char *)malloc(sizeof(char) * (maxLen + 1));
memcpy(res, str + start, maxLen);
res[maxLen] = '\0'; // C语言的细节处理
return res;
}
复制
上述代码的运行结果如下:
atoi函数自实现
此函数的实现需要注意以下几点:
忽略字符串前导空格
注意整数的正负号
只转换第一个整数,后续的字符串直接丢弃
注意int的范围
C语言代码如下:
int myAtoi(char *str){
if(str == NULL) return 0;
while(*str == ' ') str++; // 跳过前导空格
if(*str == '\0') return 0;
if(*str >= 'a' && *str <= 'z') return 0; // 首字母无效
if(*str >= 'A' && *str <= 'Z') return 0; // 首字母无效
int ret = 0, flag = 1;
// 符号问题
if(*str == '-'){
flag = -1;
str++;
}else if(*str == '+'){
flag = 1;
str++;
}
while(*str != '\0'){
// 计算数字大小
if(*str >= '0' && *str <= '9'){
ret = ret * 10 + *str - '0';
str ++;
}else {
break;
}
// int溢出处理
if((int)ret != ret){
if(flag == -1) ret = pow(2, 31);
else if(flag == 1) ret = pow(2, 31) - 1;
break;
}
}
ret *= flag;
return ret;
}
复制
上述代码的运行结果如下:
strcpy自实现
此题面试中极为常见,实现也较为简单,C语言代码如下:
char *myStrcpy(char *dest, const char *src){
if(!dest || !src) return NULL;
char *ret = dest;
while((*dest++ = *src++) != '\0');
return ret;
}
复制
翻转字符串里的单词
此题给定一字符串,字符串里的单词由一个或者多个空格分开,要求将字符串里的单词翻转,单词之间由一个空格隔开;由于此题涉及到翻转,因此可考虑采用先进后出的栈作为辅助,从后往前遍历,遇到空格就出栈,否则入栈,并添加一个空格作为分隔符即可,C语言代码如下:
char *reverseWords(char *str){
if(!str) return NULL;
int len = strlen(str);
char *ret = (char *)malloc(sizeof(char) * (len + 1));
char *stk = (char *)malloc(sizeof(char* * (len + 1));
int i = 0, top = 0;
int count = 0, flag = 0;
// 从后往前遍历
for(i = len - 1; i >= 0; --i){
// 遇见单词 逐字符入栈
if(*(str + i) != ' '){
stk[top ++] = str[i];
flag = 1;
}
// 遇见空格 出栈并记录结果
if(*(str + i) == ' '){
while(top > 0){
ret[count++] = stk[--top];
}
if(flag == 1){
ret[count++] = ' ';
}
flag = 0;
}
}
// 特殊处理
if(top == 0) {
if(count > 0) count--;
}
// 清空栈,更新结果
while(top > 0){
ret[count ++] = stk[--top];
}
ret[count] = '\0';
free(stk);
return ret;
}
复制
上述代码的运行结果如下:
比较运算符的结果
输入一个条件运算符字符串,要求输出字符串的结果,示例如下:
示例一:输入:"T?2:3"输出:"2"
示例二:输入:"T?(T?F:3)" 输出:"F"
规则如下:
条件表达式仅包含0-9,T,F,:,?,数字仅为个位数
表达式从右向左结合
条件一定是T或F两者之一
表达式结果为0-9,F或T
思路分析:此题为模拟题,从右往左遍历字符串,按照规则模拟即可输出结果,C语言代码如下:
void threeEleCounter(void){
char str[100];
scanf("%s", str);
int len = strlen(str);
int i = len;
while(i > 4){
if(str[i - 1] == ':' && str[i - 3] == '?'){
if(str[i - 4] == 'T'){
str[i - 4 ] = str[i - 2];
}else if(str[i - 4] == 'F'){
str[i - 4] = str[i];
}
// 更新下一轮待计算的运算式
for(int j = i + 1; j < len; ++j){
str[j - 4] = str[j];
}
len -= 4;
i = len - 1;
}else{
i--;
}
}
if(str[0] == 'T') printf("结果为:%c\n", str[2]);
if(str[0] == 'F') printf("结果为:%c\n", str[4]);
return ;
}
复制
上述程序的执行结果如下:
后记
以上就是本文的全部内容了,C语言解决算法题时,相较于C++,少了许多现成的API接口函数,需要着重厘清指针的指向关系,否则很容易出错,欢迎大家勘误或提出有效建议(seuhyz@163.com),非常感谢大家的支持!