• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C语言 > 一些C语言中字符串的算法问题解决实例小结

一些C语言中字符串的算法问题解决实例小结

作者:wuzhekai1985 字体:[增加 减小] 来源:互联网 时间:2017-05-28

wuzhekai1985 通过本文主要向大家介绍了字符串匹配算法c语言,c语言字符串压缩算法,c语言字符串比较,c语言字符串输入,c语言字符串等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

    字符串问题是面试中经常出现的问题,这类问题有很多,难以不一。下面是几道字符串的题目,网上都能找到解答,自己实现了一下,供网友参考。感觉算法重要的是要有正确的思路,实现起来不是问题。自己一定要多思考,这样收获可能会更多一点。
       
问题1:找两个字符串的最长公共子串。
        具体描述,如果字符串一的所有字符按其在字符串中的顺序出现在另外一个字符串二中,则字符串一称之为字符串二的子串。注意,并不要求子串(字符串一)的字符必须连续出现在字符串二中。请编写一个函数,输入两个字符串,求它们的最长公共子串,并打印出最长公共子串。
    思路:算法书上一般都有介绍,就是用动态规划的思想。关键是要找到最优子结构性质,这一点比较难。另外一个经常问到的问题“求子数组的最大和”,用的也是动态规划的思想。找两个字符串最长公共子串的核心就是找最优子结构。
        设序列X = {x1,x2,…xm}和Y = {y1,y2,…yn}的最长公共子串为Z = {z1,z2,…zk},则
        1 若xm= yn且zk=xm=yn, 则Zk-1是Xm-1和Yn-1的最长公共子串
        2 若xm!=yn且zk!=xm,则Z是Xm-1和Y的最长公共子串
        3 若xm!=yn且zk!=yn,则Z是X和Yn-1的最长公共子串
         其中Xm-1= {x1,x2,…,xm-1},Yn-1 = {y1,y2,…,yn-1}Zk-1 = {z1,z2,…zk-1}
      有了上述关系,则很容易得到递推的式子。用一个二维数组 R 记录结果,其中Z[i][j]表示Xi和Yj的最长公共子串长度。
     (1)如果i = 0或j = 0,Z[i][j] = 0
     (2)如果xi和yj相等,Z[i][j] = Z[i-1][j-1] + 1
     (3) 如果xi和yj不相等,Z[i][j] = max{Z[i-1][j],Z[i][j-1]}
        基本上差不多了,但是题目要求打印最长公共子串,只要用一个数组R记录得到最长公共子串的过程,其中R[i][j]表示Z[i][j]的值是由哪个子问题的解得到的。
       参考代码:

//函数功能 : 打印最长公共子串 
//函数参数 : X为源字符串1,Y为源字符串2,R为记录的过程,row为R的行坐标,col为R的列坐标 
//返回值 :  空 
void LCS_Print(const char *X, const char *Y, int **R, int row, int col) 
{ 
  if(R[row][col] == 1) 
  { 
    LCS_Print(X, Y, R, row-1, col-1); 
    cout<<X[row-1];  //由Xi-1和Yj-1,再加上Xi或Yj得到 
  } 
  else if(R[row][col] == 2) 
    LCS_Print(X, Y, R, row-1, col); //由Xi-1和Yj得到 
  else if(R[row][col] == 3)  
    LCS_Print(X, Y, R, row, col-1); //由Xi和Yj-1得到 
  else 
    return; 
} 
//函数功能 : 求两个字符串的最大公共子串 
//函数参数 : X为源字符串1,Y为源字符串2 
//返回值 :  最大长度 
int LCS(const char *X,const char *Y) 
{ 
  if(X == NULL || Y == NULL) 
    return 0; 
 
  int lenX = strlen(X); 
  int lenY = strlen(Y); 
  if(lenX == 0 || lenY == 0) 
    return 0; 
 
  int i, j; 
  int **C = new int *[lenX+1]; 
  int **R = new int *[lenX+1]; 
 
  //初始化 
  for(i = 0; i <= lenX; i++) 
  { 
    C[i] = new int [lenY+1]; 
    R[i] = new int [lenY+1]; 
    for(j = 0; j <= lenY; j++) 
    { 
      C[i][j] = 0; 
      R[i][j] = 0; 
    } 
  } 
 
  //开始计算  
  for(i = 1; i <=lenX; i++) 
  { 
    for(j = 1; j <=lenY; j++) 
    { 
      if(X[i-1] == Y[j-1]) //字符串的下标从0开始,所以减1,即X1 = X[0] Y1 = Y[0] 
      { 
        C[i][j] = C[i-1][j-1] + 1; 
        R[i][j] = 1;  //由Xi-1和Yj-1,再加上Xi或Yj得到 
      } 
      else 
      { 
        if(C[i-1][j] >= C[i][j-1])  
        { 
          C[i][j] = C[i-1][j]; 
          R[i][j] = 2;   //由Xi-1和Yj得到 
        } 
        else  
        { 
          C[i][j] = C[i][j-1]; 
          R[i][j] = 3;   //由Xi和Yj-1得到 
        } 
      } 
    } 
  } 
  //打印最长公共子串 
  LCS_Print(X, Y, R, lenX, lenY); 
  //记录最大长度 
  int lcs = C[lenX][lenY];   
  //释放空间 
  for(i = 0; i <= lenX; i++) 
  { 
    delete [] C[i]; 
    delete [] R[i]; 
  } 
  delete C; 
  delete R; 
  R = C = NULL; 
  return lcs; 
} 
</div>

      
问题2:在字符串中删除特定元素
    具体描述,输入两个字符串,从第一字符串中删除第二个字符串中所有的字符。例如,输入”They are students.”和”aeiou”,则删除之后的第一个字符串变成”Thy r stdnts.”。
    思路:这是字符查找的一个问题,最简单的就是考察第二个字符串的每个字符,然后检查第一个字符串中有没有这个字符,有的话删除。这样的时间复杂度是O(mn)。对于查找,我们容易想到二分查找、散列这些概念。散列的查找是非常快,时间复杂度为O(1)。如果能联想到散列,那么很容易就能给出下面的解法,相信很多人都能想到。需要一个256字节的数组,记录第二个字符串中每个字符的出现情况,0表示未出现,1表示出现。然后遍历第一个字符串,针对每个字符,去查询记录数组,以决定删除与否。
   参考代码:

//函数功能 : 在字符串中删除特定字符 
//函数参数 : pSrc为源字符串,pDel为特定字符集 
//返回值 :  空 
void DeleteSpecialChars(char *pSrc, char *pDel) 
{ 
  if(pSrc == NULL || pDel == NULL) 
    return; 
  int lenSrc = strlen(pSrc); 
  int lenDel = strlen(pDel); 
  if(lenSrc == 0 || lenDel == 0) 
    return; 
  bool hash[256] = { false }; 
  for(int i = 0; i < lenDel; i++) //建立删除字符的索引 
    hash[pDel[i]] = true; 
  //开始删除 
  char *pCur = pSrc; 
  while(*pSrc != '\0') 
  { 
    if(hash[*pSrc] == false) //不用删除 
      *pCur++ = *pSrc; 
    pSrc++; 
  } 
  *pCur = '\0'; 
}

</div>

问题3:左旋转字符串,其实也可以左旋数组
   具体描述,定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部。如把字符串abcdef左旋转2位得到字符串cdefab。请实现字符串左旋转的函数。要求时间对长度为n的字符串操作的复杂度为O(n),辅助内存为O(1)。
   思路:用了一个小技巧,如果旋转的字符串为XY,其中Y是要旋转到X前面的。只要分别将子字符串 X 和 Y 翻转,然后再将整个字符串再做一次翻转即可。STL的一个算法rotate就是用了这个。
   参考代码:

//函数功能 : 将字符串翻转 
//函数参数 : pBegin指向第一个字符,pEnd指向最后一个字符 
//返回值 :  空 
void ReverseString(char *pBegin, char *pEnd) 
{ 
  if(pBegin == NULL || pEnd == NULL) 
    return; 
 
  while(pBegin < pEnd) 
  { 
    //交换字符 
    char tmp = *pBegin; 
    *pBegin = *pEnd; 
    *pEnd = tmp; 
    //往中间靠拢 
    pBegin++; 
    pEnd--; 
  } 
} 
 
//函数功能 : 将字符串左旋 n 位 
//函数参数 : pSrc为源字符串,n为左旋位数 
//返回值 :  空 
void LeftRotateString(char *pSrc, unsigned n) 
{ 
  if(pSrc == NULL || n == 0 || n > strlen(pSrc)) 
    return; 
 
  int len = strlen(pSrc); 
  ReverseString(pSrc, pSrc + n - 1); 
  ReverseString(pSrc + n, pSrc + len - 1); 
  ReverseString(pSrc, pSrc + len - 1); 
} 
</div>

  
问题4:在一个字符串中找到第一个只出现一次的字符。如输入abaccdeff,则输出b。
   思路:这一题不难,因为每个字符只有8位,因此可以用计数法。首先统计字符串中每个字符的出现次数,然后从头遍历字符串,对于当前字符,查询统计表,如果出现的次数为1,则输出该字符即可。
   参考代码:

//函数功能 : 在一个字符串中找到第一个只出现一次的字符 
//函数参数 : pStr为源字符串 
//返回值 :  目标字符 
char FirstAppearOnce(char *pStr) 
{ 
  if(pStr == NULL) 
    return '\0'; //未找到返回空字符 
 
  int count[256] = {0}; 
  char *pTmp = pStr; 
   
  while(*pTmp != '\0') //统计字符串中每个字符出现的次数 
  { 
    count[*pTmp]++; 
    pTmp++; 
  } 
  while(*pStr != '\0') //遍历字符串,找到第一个只出现一次的字符 
  { 
    if(count[*pStr] == 1) 
      break; 
    pStr++; 
  } 
  return *pStr; //



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • C语言求解最长公共子字符串问题及相关的算法分析
  • 一些C语言中字符串的算法问题解决实例小结
  • C语言中压缩字符串的简单算法小结
  • 字符串的组合算法问题的C语言实现攻略
  • C语言字符串快速压缩算法代码

相关文章

  • 2017-05-28浅析C++11中的右值引用、转移语义和完美转发
  • 2017-05-28深入理解C/C++中的写时拷贝
  • 2017-05-28实例讲解C++编程中的虚函数与虚基类
  • 2017-05-28C++中的内存分区介绍
  • 2017-05-28C++实现的分布式游戏服务端引擎KBEngine详解
  • 2017-05-28c语言中用位运算实现加法技巧介绍
  • 2017-08-30数组作为函数参数、scanf初始化指针
  • 2017-05-28qt实现倒计时示例
  • 2017-05-28C语言 以数据块的形式读写文件详解及实现代码
  • 2017-05-28C语言中获取进程识别码的相关函数

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • c语言swap(a,b)值交换的4种实现方法
    • static_cast,dynamic_cast,reinterpret_cast和const_cast的区别详解
    • C++获得其他程序窗体控件中信息的方法
    • C++深度优先搜索的实现方法
    • C++中四种加密算法之DES源代码
    • 解析Linux内核的基本的模块管理与时间管理操作
    • c语言多线程编程使用示例
    • C/C++中退出线程的四种解决方法
    • C 语言指针变量详细介绍
    • C语言实现返回字符串函数的四种方法

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有