暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

字符串算法题选讲

Code小燕儿 2021-09-01
615

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 == 1return 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函数自实现

        此函数的实现需要注意以下几点:

        1. 忽略字符串前导空格

        2. 注意整数的正负号

        3. 只转换第一个整数,后续的字符串直接丢弃

        4. 注意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(231);
                      else if(flag == 1) ret = pow(231) - 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"

              规则如下:

              1. 条件表达式仅包含0-9,T,F,:,?,数字仅为个位数

              2. 表达式从右向左结合

              3. 条件一定是T或F两者之一

              4. 表达式结果为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),非常感谢大家的支持!


                文章转载自Code小燕儿,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                评论