第【5】章: 字符串 学习报告

 

(5.1)节 判断字符串有无重复元素

1、题干:

 

 

 

2、解答思路:在ascii码中,字符对应的int是0-127,所以创建128大小的数组,对原字符串进行计数,然后遍历数组,如果出现大于1的说明出现了两次以上,有重复。

如不能创建空间,那么使用比较查找,遍历每一个元素,在后面字符串查找,找到了说明重复。O(n(n-1)/2)=O(n^2).优化可以先进行排序后再比较相邻两个字符是否相等;O(nlgn+n)

3、关键代码

int text(char a[],int t)//t为字符的个数 ,加末尾空字符

{int d[128];

for(int i=0;i<128;i++)//建立128大小的数组,初始化0

d[i]=0;

for(int i=0;i<t;i++)//如不比较最后那个自带的,可以t-1

{

d[a[i]]++;

}

for(int i=0;i<128;i++)

if(d[i]>1)

return 1;

return 0;

}

(5.2)节 翻转字符串

1、题干:

将字符串倒过来;

2、解答思路: 创建一个与字符串一样长度的字符数组,将源字符串从后面开始—遍历的值赋予新的数组++;

3、关键代码:

void text(char a[],int t)//t为字符的个数 ,加末尾空字符

{

char r[t+1];

int j=0;

for(int i=t-2;i>=0;i--)

{r[j]=a[i];

j++;}

 

for(int i=0;i<t-1;i++)

a[i]=r[i];

}

(5.3)节 变形词问题

1、题干:判断,两个字符串能否变成相互演变

2、解答思路:首先这两个字符串必须有相同长度,其次要有相同的元素,跟第一题差不多,创建128大小的数组,轮流对两个字符串进行计数,如果出现奇数,则,两个字符串有不同的元素,则不能变形。

3、关键代码:#includ<cstring>  strlen()获取字符串长度;

 int text(char a[],char b[])

{

int r[128];

for(int i=0;i<128;i++)

r[i]=0;

if(strlen(a)!=strlen(b))

return 0;

for(int i=0;i<strlen(a);i++)

{

       r[a[i]]++;r[b[i]]++;

}

for(int i=0;i<128;i++)

if(r[i]&1)///当r[i]为奇数时为真,则不能变形返回0

return 0;

return 1;

}

 

(5.4)节 替换掉字符串中的空格

1、题干:在原字符串中,选择将要替换掉的子字符串进行替换;

2、解答思路:用字符数组建立的字符串有诸多的限制;C++为我们提供了string类,可以方便我们的操作

3、关键代码

string text(string a,string b,string c)//将a字符串中的所有b子字符串替换成c

{

int count=0;//子字符串的个数

int t=0;

string r;

for(int i=0;i<a.size();i++ ) //count统计个数

       {

       while(a[i]==b[t])//t表示循环的次数

       {

       if(t==b.size()-1)

              {r+=c;

              count++;

              i+=b.size();

              break;}

       i++;t++;

       }

       i-=t;t=0;

       r+=a[i];

       }

if(count==0)

return "替换失败,找不到子字符串";

 

return r;//返回替换好的字符串 

}

 

(5.5)节 压缩字符串

1、题干:

 

 

 

2、解答思路:对字符串进行遍历计数, 然后再根据数量生成新的字符串

利用stringstream:使用stringstream的时候要注意加#include"sstream"。比如说我要把int类型的23转为string类型,那么我可以这样实现:

  1. int a = 23;
  2. stringstream ss;
  3. ss << a;
  4. string s1 = ss.str();

 

3、关键代码:

#include<sstream>

string text(string a)

{

int r[128];

for(int i=0;i<128;i++)//初始化

r[i]=0;

for(int i=0;i<a.size();i++)

r[a[i]]++;

string str;

for(int i=0;i<128;i++)

{

if(r[i]>0)

       {str+=i;

       stringstream t;///

       t<<r[i];//将int转换成string

       str+=t.str();

       }

}

if(str.length()<a.length())//若压缩后比原来还长则返回原来

return str;

else return a;

}

 

(5.7)节 旋转词

1、题干:

 

 

 

2、解答思路:要判断a是否可以由b旋转后得到。可以将把字符串b加上他本身,如果可以的话,那么a就在于两个b的交界处;

3、关键代码:
int text(string a,string b)

{

string str=b+b;

int j=0;

for(int i=0;i<str.size();i++)

       {

       while(a[j]==str[i])

       {if(j==a.size()-1)

              return 1;

       i++;j++;

       }

       i-=j;j=0;

}

return 0;

}

 

(5.8)按单词翻转

1、题干

比如 That is my home,翻转后就是tahT si ym emoh

2、解答思路:设置边界,扫描到空格为一个单词,设置两个指针表示一个单词,进行翻转

3、关键代码:

 

(5.9)去掉连续出现的k个0

1、题干:

去掉字符串中k个连续出现的0

2、解答思路:遍历字符串,建立两个指针指定0的区间,将区间的大小对k进行取余,余数为该区间剩余的0的个数;

3、关键代码:

string text(string a,int k)

{

int L=0;

int count=0;

string str;

for(int i=0;i<a.size();i++)

       {

              while(a[i]==48)//0的 ASCII码序号为48;

                     {i++;count++;}

              while (count%k)

                      {count--;str+=48;     }   

              str+=a[i];     

}

return str;

}

 

(5.10)神奇的回文串

1、题干:字符串是否为回文字符串

2、解答思路:回文字符串,正着念和反着念是一样的。所以求出字符串的逆序列,两个字符串如果一样就返回true

3、关键代码

(5.11)节 最短按摘要生成

1、题干

 

 

 

2、解答思路:暴力破解,找出所有关键字的所有位置,记录起来,通过比较找出包含所有关键字的最短的子字符串

3、关键代码:略

(5.12)节

(5.13)节  字符串匹配  Rabinkarp

1、题干:

2、解答思路:通过对子串求出哈希值,然后对源字符串每K个连续的字符串进行求哈希值(滚动哈希),并存储在数组里,然后与子串的哈希值比较。

3、关键代码:

long hash(string s,int begin,int end,int hc)///在原串中,从begin开始end个字符获取参数为hc的哈希值

{int hash=0;

for(int i=0;i<end;i++)

       hash=(hash*hc+s[i]);

return hash;

}

int st(int x,int n)//求x的n次方

{

for(int i=1;i<n;i++)

x*=x;

return x;

}

void haout(string a,string b,int hc)

{

       long hsz[a.size()-b.size()+1];///存储a源字符串所有b一样长度的哈希值

       if(a.size()<b.size())

       {cout<<"错误,源字符串比子串短";

       return;

       }

       int bhs=hash(b,0,b.size(),hc);///b的哈希值

       hsz[0]=hash(a,0,b.size(),hc);

       for(int i=1;i<=a.size()-b.size();i++)

       //将a的b长度哈希值 存储在haz数组中,下标表示a中子串的起始位置

{//   前一个哈希值*hc减去第一个,然后再加上新的一个

       hsz[i]=(hsz[i-1]*hc-a[i-1]*st(hc,b.size()))+a[i+b.size()-1];

}

       for(int i=0;i<=a.size()-b.size();i++)

              if(hsz[i]==bhs)///找出哈希值与b相同的串第一个元素的下标

              //哈希值在某种程度会出现哈希误差,即不同的子串计算出相同的哈希值

              //因此可以在找到相同的哈希值是进行朴素验证,即一个个比较

                     cout<<i<<endl;

}

 

(5.14)节  

(5.15)节 字符串匹配  KMP

1、题干:

2、解答思路:通过子串建立next数组,优化暴力匹配,原数组循循渐进,子数组不匹配时返回next数组中指向的位置进行匹配

3、关键代码:

int tet(string s,string a)///建立next数组

{

      

if(a.size()>s.size())

       return -1;     

      

       int next[a.size()];

       next[0]=-1;

       next[1]=0;

       int j=1;

       int k=next[j];

       while(j<a.size()-1)

              if(k<0||a[j]==a[k])

                     next[++j]=++k;

              else

              k=next[k];

///////////////////////查找

j=0;

int i=0;

while(i<s.size())

{

       if(j==-1||s[i]==a[j])

             {j++;i++;

             }

       else

             j=next[j];

      if(j==a.size())     

             return (i-j);   ///返回第一个位置     

       }

return -1;

}

 

(5.16)节

(5.17)节

(5.18)节   后缀数组

1、题干:子串一定是某个后缀的前缀

2、解答思路:

3、关键代码:

建立后缀数组:

string tet(string s,int i)

{

string a;

       for(int j=i;j<s.size();j++)

       a+=s[j]; ///创建后缀

return a;

}

string b="bababb";///原数组

string a[b.size()];//存后缀的数组

for(int i=0;i<b.size();i++)

    a[i]=tet(b,i);//建立后缀数组

 

posted @ 2019-12-04 15:58  浪波激泥  阅读(227)  评论(0编辑  收藏  举报