• 代码面试之串(转载)


    串的基本概念
        串(或字符串),是由零个或多个字符组成的有穷序列。含零个字符的串称为空串,用Ф表示。
        串中所含字符的个数称为该串的长度(或串长)。
        当且仅当两个串的长度相等并且各个对应位置上的字符都相同时,这两个串才是相等的。
        一个串中任意个连续字符组成的子序列(含空串,但不含串本身)称为该串的子串。例如,“a”、“ab”、“abc”和“abcd”等都是“abcde”的子串(平凡子串不包括自身)。

    问题: “abcde”有多少个平凡子串?
    解:    空串数:1
        含1个字符的子串数:5
        含2个字符的子串数:4
        含3个字符的子串数:3
        含4个字符的子串数:2
    共有1+2+3+4+5=15个子串。


    串的存储结构

    串的顺序存储及其基本操作实现
          串是一种特殊的线性表,在非紧缩格式中,它的每个结点仅由一个字符组成,因此存储串的方法也就是存储线性表的一般方法。存储串最常用的方式是采用顺序存储,即把串的字符顺序地存储在内存一片相邻的空间,这称为顺序串。

    串的非紧缩格式(一个单元存放一个字符)与串的紧缩格式(一个单元存放多个字符) ... ... 

    顺序存储采用一般顺序表的存储结构,其类型定义如下:

    #define MaxSize 100
    typedef struct
    {
      char data[MaxSize];
      int len;
    } strtype;//[紧缩格式]

         其中,ch域用来存储字符串,len域用来存储字符串的当前长度,MaxSize常量表示允许所存储字符串的最大长度。在C语言中每个字符串以''标志结束(在这个结构体中不需要用''标志结束,以下标为0开始存入字符)。

    ASCII比较字符串
      由于 "大写字母<小写字母" ,并且a<b,因此在比较时ASCII大的字母比较靠前,但要特殊考虑大小写夹杂的情况

    串的链式结构存储
        链式方式存储串,即用单链表形式存储串。这称为链式串或链串。
    链串中的结点类型定义:

    typedef struct snode
    {    char data;
         struct snode *next;
    } LiString;


    例:在链串中,设计一个算法把最先出现的子串"ab"改为"xyz"。    
    解:在串s中找到最先出现的子串"ab",p指向data域值为'a'的结点,其后为data域值为'b'的结点。将它们的data域值分别改为'x'和'z',再创建一个data域值为'y'的结点,将其插入到*p之后。本例算法如下:

    复制代码
    void Repl(LiString *&s)
    {    
        iString *p=s->next,*q;int find=0;
        while (p->next!=NULL && find==0)
        {     
            if (p->data==‘a’ && p->next->data==‘b’)  /*找到*/    
            {   p->data='x';p->next->data='z';        
                   /*替换为xyz*/
                    q=(lstring *)malloc(sizeof(lstring));
                    q->data='y';q->next=p->next;
                    p->next=q;
                    find=1;
                   }
                   else p=p->next;
            }
    }
    复制代码

    扩展,编写一个算法实现替换字符串(提示:查找(串的模式匹配,见下面的介绍)、替换相结合)
    --------------------------------------------------------

    重点:
    串的模式匹配————(本人认为较难,很难很难,不过绝对值得一学,学会了有成就感
        设有主串s和子串t,子串t的定位就是要在主串s中找到一个与子串t相等的子串。通常把主串s称为目标串,把子串t称为模式串,因此定位也称作模式匹配。模式匹配成功是指在目标串s中找到一个模式串t;不成功则指目标串s中不存在模式串t。 

    算法一:BF算法(Brute-Force)
        Brute-Force简称为BF算法,亦称简单匹配算法,其基本思路是:
        从目标串s="s0s1…sn-1"的第一个字符开始和模式串t="t0t1…tm-1"中的第一个字符比较,若相等,则继续逐个比较后续字符;否则从目标串s的第二个字符开始重新与模式串t的第一个字符进行比较。依次类推,若从模式串s的第i个字符开始,每个字符依次和目标串t中的对应字符相等,则匹配成功,该算法返回i;否则,匹配失败,函数返回-1。 

    一种实现:

    复制代码
    int indexpos(SqString str,SqString substr)
    {    int i,j,k,idx=-1;
        for (i=0;i<str.len;i++)
        {   
             for (j=i,k=0;str.data[j]==substr.data[k];j++,k++);
             if (k==substr.len) //注意j每次从i开始,有回溯
                      return(i);
        }
        return(-1);
    }
    复制代码


    二种实现:

    复制代码
    int index(SqString s,SqString t)
    {  
        int i=0,j=0,k;
        while (i<s.len && j<t.len)
        {    if (s.data[i]==t.data[j])      /*继续匹配下一个字符*/
        {     i++; j++;  }   /*主串和子串依次匹配下一个字符*/
        else     /*主串、子串指针回溯重新开始下一次匹配*/
        {     
                      i=i-j+1;     /*主串从下一个位置开始匹配*/
                      j=0;            /*子串从头开始匹配*/
                }
         }
         if (j>=t.len)   k=i-t.len;     /*返回匹配的第一个字符的下标*/
         else  k=-1;                /*模式匹配不成功*/
         return k;
      } 
    复制代码


    上面这两个算法都不怎么难理解~~
    关键是下面这个KMP模式匹配算法:

    算法二:
    如今呢我也是,似懂非懂,半懂加不懂~~~
    当然里面最重要的一步就是求next数组~~~
    next数组的功能是,字符串在匹配失效时,主串不用再向前做回溯操作即没有 i=i-j+1; 这步
    而只对模式串做右滑操作,到底右滑多少,由next对应模式失配的下标决定。
    而相应next数组的产生只取决模式自身,其证明亦很简单
    关键是如何得到next数组。。。。

    串的操作实现代码如下:

    //串的顺序存储..
    //结构体定义..
    #include<stdio.h>
    #define MAX 100
    typedef struct
    {
     char S[MAX];
    }SString;
    //串的初始化..
    void Init_Str(SString &SS)
    {
     for(int i=0;i<MAX;i++)
     {
      SS.S[i]='';  //把所有值都赋''..
     }
    }
    
    //求串的长度..
    int Length_Str(SString SS)
    {
     int length=0;
     while(SS.S[length]!='')  //不是''的话就累加起来,知道最后就知道了长度..
     {
      length++;
     }
     return length;
    }
    
    //串的赋值..
    void StrEvaluate(SString &SS,char S1[])
    {
     for(int i=0;S1[i]!='';i++)  //这语句前面可以初始化一下SS.S[]也行..
     {
      SS.S[i]=S1[i];
     }
    }
    
    //串的链接..
    void StrConcat(SString &SS,SString &S1)
    {
     int len1,len2;
     len1=Length_Str(SS);
     len2=Length_Str(S1);
     if(len1+len2+1<MAX)
     {
      for(int i=0;i<len2;i++)
      {
       SS.S[len1+i]=S1.S[i];
      }
     }
     else
     {
      printf("你输入的字符串长度超过了MAX!!!");
     }
    }
    
    //求串的字串..
    SString SubStr(SString &SS,int i,int length) //SS的第i个位置开始去length长的字串..然后返回..
    {
     SString S1;
     Init_Str(S1);
     if(i+length<Length_Str(SS))  //判断字串的长度是否合法..
     {
      for(int j=i;j<=i+length;j++)
      {
       S1.S[j-i]=SS.S[j];
      }
     }
     else
     {
      printf("所取的length超出主串的长度!!!");
     }
     return S1;
    }
    
    //串的比较..
    int StrComp(SString S1,SString S2)
    {
     int i=0;
     while(S1.S[i]==S2.S[i]&&S1.S[i]!='')  //第一个元素开始判断是否相等..不相等的话来判断那个大那个小..
     {
      i++;
     }
     if(S1.S[i]==S2.S[i])
     {
      return 0;
     }
     else if(S1.S[i]>S2.S[i])
     {
      return 1;
     }
     else
     {
      return -1;
     }
    }
    
    //主函数..
    int main()
    {
     int k=0,len=0;
     SString SS,S1,S2,S3;
     char ch1[20]={'a','b','c','d','e','f'};
     char ch2[20]={'k','l','n','m','j','k'};
     char ch3,ch4,ch5,ch6,ch7,ch8,ch9;
     char flag=1,flag1=1;
     while(flag)
     {
      printf("**************************************
    ");
      printf("*	1  初始化串
    ");
      printf("*	2  求串的长度
    ");
      printf("*	3  串的赋值
    ");
      printf("*	4  串的链接
    ");
      printf("*	5  求字串
    ");
      printf("*	6  串的比较
    ");
      printf("*	11 推出程序
    ");
      printf("**************************************
    ");
      scanf("%c",&ch3);
      switch(ch3)
      {
      case '1':
       while(flag1)
       {
       printf("	---------------
    ");
       printf("-	1. SS初始化
    ");
       printf("-	2. S1初始化
    ");
       printf("-	3. S2初始化
    ");
       printf("	---------------
    ");
       scanf("%c",&ch4);
       switch(ch4)
       {
       case '1':
        Init_Str(SS);
        printf("SS初始化成功!");
        break;
       case '2':
        Init_Str(S1);
        printf("S1初始化成功!");
        break;
       case '3':
        Init_Str(S2);
        printf("S2初始化成功!");
        break;
       case '4':
        flag1=0;
        printf("renyijian!!");
              //default:
       } 
            
       getchar();
       }
    
      case '2':
             printf("	---------------
    ");
       printf("-	1. 求SS长度
    ");
       printf("-	2. 求S1长度
    ");
       printf("-	3. 求S2长度
    ");
       printf("	---------------
    ");
       scanf("%c",&ch5);
       switch(ch5)
       {
       case '1':
        len=Length_Str(SS);
        printf("SS长度=%d",len);
        break;
       case '2':
        len=Length_Str(S1);
        printf("S1长度=%d",len);
        break;
       case '3':
        len=Length_Str(S2);
        printf("S2长度=%d",len);
        break;
       default:
        printf("changdu
    ");
       }
      case '3':
       while(flag)
       {
                printf("	---------------
    ");
       printf("-	1. SS赋值
    ");
       printf("-	2. S1赋值
    ");
       printf("-	3. S2赋值
    ");
       printf("	---------------
    ");
       scanf("%c",&ch6);
       switch(ch6)
       {
       case '1':
        StrEvaluate(SS,ch1);
        printf("SS赋值成功
    !");
        break;
       case '2':
        StrEvaluate(S1,ch2);
        printf("S1赋值成功
    !");
        break;
       case '3':
        StrEvaluate(S2,ch1);
        printf("S2赋值成功
    !");
        break;
       //default:
        //printf("fuzhi
    ");
       }
       getchar();
       }
      case '4':
                printf("	---------------
    ");
       printf("-	1. SS和S1链接
    ");
       printf("-	2. SS和S2链接
    ");
       printf("-	3. S1和S2链接
    ");
       printf("	---------------
    ");
       scanf("%c",&ch7);
       switch(ch7)
       {
       case '1':
        StrConcat(SS,S1);
        printf("SS和S1链接成功!");
        break;
       case '2':
        StrConcat(SS,S2);
        printf("SS和S2链接成功!");
        break;
       case '3':
        StrConcat(S1,S2);
        printf("S2和S1链接成功!");
        break;
       default:
        printf("lianjie
    ");
       }
      case '5':
                printf("	---------------
    ");
       printf("-	1. SS的字串
    ");
       printf("-	2. S1的子串
    ");
       printf("-	3. S2的子串
    ");
       printf("	---------------
    ");
       scanf("%c",&ch8);
       switch(ch8)
       {
       case '1':
        S3=SubStr(SS,3,3);
        break;
       case '2':
        S3=SubStr(S1,3,3);
        break;
       case '3':
        S3=SubStr(S2,3,3);
        break;
       default:
        printf("zichuan
    ");
       }
                case '6':
                printf("	---------------
    ");
       printf("-	1. SS和S1比较
    ");
       printf("-	2. SS和S2比较
    ");
       printf("-	3. S1和S2比较
    ");
       printf("	---------------
    ");
       scanf("%c",&ch9);
       switch(ch9)
       {
       case '1':
        k=StrComp(SS,S1);
        printf("%d",k);
        printf("SS和S1比较成功!");
        break;
       case '2':
        k=StrComp(SS,S2);
        printf("%d",k);
        printf("SS和S2比较成功!");
        break;
       case '3':
        k=StrComp(S1,S2);
        printf("%d",k);
        printf("S2和S1比较成功!");
        break;
       default:
        printf("比较
    ");
       }
      case '11':
       flag=0;
       printf("任意键结束程序..");
      }
      getchar();
     }
     return 0;
    }
  • 相关阅读:
    ajax和axios的http请求及响应数据时候区别及拦截时候的方法,属性等
    超简单的抖音去水印原理教程
    Azure DevOps Server 的连接源(Artifacts):六、发布python程序(Twine pip)
    Azure DevOps Server 的连接源(Artifacts):五、python包管理pip和twine
    更改Azure DevOps Server的原生界面(七、禁用浏览器下载和以zip格式下载文件)
    Azure DevOps Server 的连接源(Artifacts):九、vue示例和自动打包
    Azure DevOps Server 的连接源(Artifacts):七、NPM 基础知识
    Azure DevOps Server 的连接源(Artifacts):二、NuGet包管理
    Azure DevOps Server 的连接源(Artifacts):四、python基础(Django、Flask)
    Azure DevOps Server 的连接源(Artifacts):一、概述
  • 原文地址:https://www.cnblogs.com/lihuidashen/p/4850648.html
Copyright © 2020-2023  润新知