《程序员面试宝典》部分字符串题目

// 1.题目:求一个字符串中连续出现次数最多的子串 《程序员面试宝典》P225

/*基本算法描述:
理解(一):
    给出一个字符串abcbcbcabc
    1.穷举出所有的后缀子串
        substrs[0] = abcbcbcabc;
        substrs[1] = bcbcbcabc;
        substrs[2] = cbcbcabc;
        substrs[3] = bcbcabc;
        substrs[4] = cbcabc;
        substrs[5] = bcabc;
        substrs[6] = cabc;
        substrs[7] = abc;
        substrs[8] = bc;
        substrs[9] = c;
    1.第一行第一个字符a,与第二行第一个字符b比较,不等,则
    2.第一行前两个字符ab,与第三行前两个字符cb比较,不等,则
    3.第一行前三个字符abc,与第四行前三个字符bcb比较,不等,则
    4.第一行前四个......
    上述过程就相当于在原始字符串中,
    第一趟,a与b比较,ab与cb比较,abc与bcb比较,abcb与cbca比较,abcbc与bcabc比较,abcbcb与cabc比较......
    第二趟,b与c比较,bc与bc比较(相等,则继续向后取长度为2的子串比较(子串间隔j-i),碰到不等为止,本例中因碰到ab停止),bcb与cbc比较......
    第三趟,c与b比较,cb与cb比较(相等),cbc与bca比较......
*/

#include <iostream>
#include <string>
#include <vector>
#include <utility>
#include <stdio.h>


using namespace std;
pair<int,string> fun(const string &str)//求一个字符串中连续出现次数最多的子串,输出子串以及出现的次数
{
    int count = 1, maxcount = 1;
    vector<string> substrs;
    string substr;
    int len = str.length();
    cout<<"所给字符串的子串如下:"<<endl;
    for(int i = 0; i < len; i++)
    {
        substrs.push_back(str.substr(i));//str.substr(i,length)表示从第i个开始截取length的长度,如果length为空,则截取到结尾。
        cout<<substrs[i]<<endl;
    }
            cout<<count<<endl;

    for(int i = 0; i < len; i++)//遍历趟数
    {
        for(int j = i+1; j < len; j++)//每一趟,某一行与其他行的比较
        {
            count = 1;//此处要重新给count赋值,因为循环后count已经累加过了
            if(substrs[i].substr(0,j-i) == substrs[j].substr(0,j-i))//注意这里参与比较的个数实际是j-i,而非j-1,因为j随着i增大了
            {
                count++;
//方法一:同一子串选择不同的起点
                for(int m = 1 ;(j-i)*m < len-j; m++)//len-j 是第j行的长度
                {
                    if(substrs[i].substr(0,j-i) == substrs[j].substr(m*(j-i),j-i))//注意这里第二个匹配的起点其实是j-i,因为substrs下标从0开始
                        count++;
                    else
                        break;
                }
//方法二:选择不同子串进行匹配
//                 for(int k=j+(j-i); k<len; k+=j-i)  
//                 {  
//                     if (substrs[i].substr(0,j-i) == substrs[k].substr(0, j-i))  
//                         ++count;  
//                     else  
//                         break;  
//                 }  

                if(count > maxcount)
                {
                    maxcount = count;
                    substr = substrs[i].substr(0,j-i);
                }
                
            }
        }

    }
    return make_pair(maxcount,substr);
}

// 2.题目:输入一行字符串,输出其中出现的相同且长度最长的字符串及其首字符位置 《程序员面试宝典》P226
/*算法描述:
    首先将字符串分解成后缀子串,根据题目一的思想,最长字符串的相同字符串的首字符必然相同,找到首字符相同的后
    接着往下比较,直到遇到不同的或者字符串末尾,记下这段字符串,赋值给maxstr。下次循环的时候得到字符串后与
    maxstr长度比较,如果比之大就赋值给maxstr。循环结束,返回maxstr和首字符。
        substrs[0] = abcbcbcabc;
        substrs[1] = bcbcbcabc;
        substrs[2] = cbcbcabc;
        substrs[3] = bcbcabc;
        substrs[4] = cbcabc;
        substrs[5] = bcabc;
        substrs[6] = cabc;
        substrs[7] = abc;
        substrs[8] = bc;
        substrs[9] = c;
*/
pair<int, string> fun1(const string &str)
{
    vector<string> substrs;
    int pos = 0, len = str.length();
    //cout<<"子串如下"<<endl;
    for(int i = 0; i < len; i++)
    {
        substrs.push_back(str.substr(i));
        //cout<<substrs[i]<<endl; //输出后缀子串
    }
    string maxstr = "\0";//默认最长为空
    //cout<<"maxstr默认长度"<<maxstr.length()<<endl;
    
    for(int i = 0; i < len; i++)
        for(int j = i+1; j < len; j++)
        {
            if(substrs[i].substr(0,1) == substrs[j].substr(0,1))
            {
                //初始化
                if (maxstr.length() < 1)
                {
                    pos = i+1;
                    maxstr = substrs[j].substr(0,1);
                }

                for(int m = 1; m < len-j; ++m)
                {    
                    if(substrs[i].substr(m,1) == substrs[j].substr(m,1))//依次比较字符
                    {
                        if(m+1 > maxstr.length())//如果找到更长的串,重新给pos和maxstr赋值
                        {
                            pos = i+1;
                            maxstr = substrs[i].substr(0,m+1);
                        }

                    }
                    else
                        break;                    
                }
            }
        }
        return make_pair(pos,maxstr);
}

//其他实现方法 http://blog.csdn.net/jimoshuicao/article/details/10163121#cpp
pair<int,string> fun2(const string &str)      
{      
    int index=0;      
    int maxlen=0;      
    string substr;      
    int i=0,j=0;      
    int len=str.length();      
    int k=i+1;      
    int s,lt;    
    while(i<len)
    {      
        j=str.find(str[i],k); //从(k~len-1)范围内寻找str[i]      
        if(j==string::npos  )//若找不到,说明(k~len-1)范围内没有str[i]      
        {      
            i++;      
            k=i+1;      
        }
        else
        { //若找到,则必有(j>=i+1)      
            s=i;       
            lt=1;      
            while(str[++s]==str[++j] && j<len){}      
            lt=s-i;      
            if(lt>maxlen)      
            {      
                maxlen=lt;      
                substr=str.substr(i,lt);      
                index=i+1;      
            }      
            k=j;      
        }//else      
    }//while      
    return make_pair(index,substr);      
}    

/*   书中程序思想: 按照长度递减去寻找相同的子串,只要找到第一对相同的子串,则立刻退出程序。
因为是按照长度递减的顺序去寻找子串,所以必定能找到最长的相同子串。

以abcab为例子分析如下:

首先寻找长度为4的子串,只能是abca和bcab,再查看这两个子串是否有其他相同的子串。有的话直接输出结果并退出程序。

然后寻找长度为3的子串,只能abc,bca,cab。这3个子串都没有其他相同的子串。

最后寻找长度为2的子串,首先是ab,用find函数返回在abcab中正序查找的位置0,用rfind函数返回在abcab中逆序查找的位置3。
这两个位置不相等,说明在不同的位置存在相同的子串ab。直接输出ab:1,然后退出程序。
*/
pair<int, string> fun3(const string &str)
{
    int pos = 0;
    int len = str.length();
    string maxlen = "\0";
    for(int j = len-1; j >= 1; j--)//控制查找的字符串长度,从最长的开始查找
        for (int i = 0; i+j <= len; i++)//控制开始查找的位置
        {
            if (str.find(str.substr(i,j),i+1) != string::npos)//对每一个串str.substr(i,j),从i+1开始查找,只要找到就赋值返回
            //if (str.find(str.substr(i,j)) != str.rfind(str.substr(i,j))) //如果正序查找返回的结果和逆序查找返回结果不一样,也说明找到了。
            {
                pos = i+1;
                maxlen = str.substr(i,j);
                return make_pair(pos,maxlen);   
            }
        }
}

//题目3:写一个程序,模拟C++的strstr()函数:给定主串和子串,在主串中查找子串,返回从第一个子串开始的所有主串剩下的部分
//例如给定主串“abcdgdf”和子串“cdg”,返回“cdgdf”

/*分析:
首先把子串第一个字符与主串第一个字符比较,如果不相等,i++继续与主串下一个位置比较;如果找到相等的,比较子串剩下的字符,
一旦有一个不相等,i++与主串下一个比较,如果到了子串末尾了还都相同,则说找到匹配,则输出*/
char *strstr1(string &str, string &substring)
{
    int flag = 0;
    int i = 0, m = 0,j = 0;
    //string sstr;
    while(!flag && str[i] != '\0')//设置标志位,如果找到匹配的,立即结束整个循环;如果搜索到主串末尾还没搜到,也结束
    {
        for(j = 0; substring[j] != '\0'; j++)//子串范围内比较
        {
            if(substring[j] != str[i+j])//一旦找到不相等的,立即跳出循环,移动主串指针到下一个
            {
                flag = 0;
                break;
            }
            else if(substring[j+1] == '\0')//如果全部想等,并且已经比较到子串末尾了,证明找了匹配了,flag置1,
            {                            //结束整个循环。一定注意是“==”!!!,一点错误,查了好久!
                flag = 1;
                break;
            }
        }
        i++;//移动主串的指针,指向下一个
    }
    if(str[i] != '\0')//如果是因为找到匹配的而非是因为到了主串末尾而结束,才输出
    {
//         for(int k = i-1; str[k] != '\0'; k++)
//             sstr[m++] = str[k];
//         sstr[m] = '\0';
        return &str[i-1];//直接返回这个指针,输出的时候就是这个指针之后的整个字符串
    }
    else
        return NULL;//没找到,返回空

}
/*题目4:将一句话里的单词倒置,标点符号不到换。如I come from China. 变成China. from come I   《程序员面试宝典》P225
分析1:从后到前,以空格为分界线,利用"+"连接字符串(或者apend()函数)直接进行字符串连接。
分析2:思路和1差不多,利用容器
分析3:先整体反转,然后再把每个单词反转*/
//char *senrev(string &str)
string senrev(string &str)
{
    //string str = "I come from China.";
    vector<string> svec;
    if(str.empty())//首先确定字符非空
        return NULL;
    int m = 0;
    int j = str.length()-1;//
//    int j = 0;
    string revstring;

    //思路2,利用容器
//     for(int i = 0; i <= str.length(); i++)
//     {
//         if(str[i] == ' ' || str[i] == '\0')//遇到空格或者结束符,就把这中间的单词加到容器里面
//         {
//             m = i;
//             svec.push_back(str.substr(j,m-j));//从j = 0开始
//             j = m+1;
//         }
//     }
//     for(vector<string>::reverse_iterator iter = svec.rbegin(); iter != svec.rend(); iter++)
//     {
//         revstring += *iter;
//         if(iter != svec.rend()-1)//只要不是最后一个单词,都需要加个空格
//             revstring += " ";
//     }

// 思路1,用append()函数连接
//     for(int i = str.length()-1; i >= 0; i--)
//     {
//         if(str[i] == ' ')//找到空格
//         {
//             m = i+1;
//             revstring = revstring.append(str.substr(m,j-i));//插入空格与j之间的字符串
//             revstring = revstring.append(" ");//只要不是第一个单词的最后,都需要插入空格
//             j = i-1;//j前移到前一个单词的终点
//         }
//         if(i == 0)//如果到了字符串开始,就插入第一个单词,即起点为0,长度为m-1的子串
//             revstring = revstring.append(str.substr(0,m-1));
//         
//     }
// 思路1,用“+”连接
    for(int i = str.length()-1; i >= 0; i--)
    {
        if(str[i] == ' ')//搜索空格
        {
            m = i+1;
            revstring += str.substr(m,j-i);//插入空格与j之间的字符串
            revstring += " ";//只要不是第一个单词的最后,都需要插入空格
            j = i-1;//j前移到前一个单词的终点
        }
        if(i == 0)//如果到了字符串开始,就插入第一个单词,即起点为0,长度为m-1的子串
            revstring += str.substr(0,m-1);

    }
     return revstring;

}

/*题目5:字符串压缩。通过键盘输入一串小写字母(a~z)组成的字符串相同字符串用数字代替
。例如 输入gaaabbbbccddde 压缩后成 g3a4b2c3de
思路:首先指针指向字符串第一个字符,如果下一个字符与这个字符不同,直接将这个字符加到
新字符串上;如果与下一个字符串相同,得到相同字符的个数,把这个数字转换成字符并连同这
个字符一起加到新字符上,指针指向下一个新字符。直到程序结尾。*/
string strzip(string &str)
{
    string zipstr;
    int len = str.length();
    int j = 0, count = 1;
    char tempstr[8];
    
    for(int i = 1; i <= len; i++)
    {
        if(str[j] == str[i])//如果下一个字符和当前字符相同,count加一
            count++;
        else//遇到不同的字符,准备写入新字符串
        {
            if(count == 1)//如果只有一个,直接写入这个字符
                zipstr += str[j];
            else
            {
//                 char tempstr[8] = {0};
//                 sprintf(tempstr,"%d",count);
//                 zipstr = zipstr + tempstr + str[j];
                memset(tempstr,0,8);//每次,把tempstr置零,方便写入count
                zipstr = zipstr + itoa(count, tempstr, 10) + str[j]; //直接把字符串连接起来
            }
                count = 1;//写完之后,count置1
                j = i;//j指针移动到下一个未写的字符上
            
        }
    }
    return zipstr;
}

//完全用sprintf,有问题
// char *strzip1(string &str)
// {
//     char zipstr[100];
//     int len = str.length();
//     int j = 0, count = 1;
//
//     for(int i = 1; i <= len; i++)
//     {
//         if(str[j] == str[i])
//             count++;
//         else
//         {
//             if(count == 1)
//                 sprintf(zipstr+strlen(zipstr),"%c",str[j]);
//             else
//             {
// //                 char tempstr[8] = {0};
// //                 sprintf(tempstr,"%d",count);
// //                 zipstr = zipstr + tempstr + str[j];
//                 //     sprintf(s, "%.*s%.*s", sizeof(a1), a1, sizeof(a2), a2);
//                 sprintf(zipstr+strlen(zipstr),"%d%c",count,str[j]);
//                 // char tempstr[8] = {0};
//                 //zipstr = zipstr + itoa(count, tempstr, 10) + str[j];
//             }
//             count = 1;
//             j = i;
//
//         }
//     }
//     return zipstr;
// }

int main()  
{   
    //string str = "aaaabcbcbcbcabccccc";  
 //    string str = "yyabcdabjcabceg";  
//     string substring;
    //string str = "abbcdfe";
    
    /*第1题
pair<int,string> rs;  
    rs=fun(str);  
    cout<<"出现次数最多的子串是: "<<rs.second<<endl<<"出现的次数是: "<<rs.first<<endl;  
    */

    /*第2题
    pair<int,string> rs;  
    rs = fun3(str);
    cout<<"位置: "<<rs.first<<endl<<"最大字符串"<<rs.second<<endl;
    */

    /*第3题*/
//     cout<<"The original string is :"<<str<<endl;
//     cout<<"Please input the substring that need to be searched:"<<endl;
//     cin>>substring;
//     if(strstr1(str,substring) == NULL)
//         cout<<"Can not find!"<<endl;
//     else
//     cout<<strstr1(str,substring)<<endl;
    
    /*第4题*/
//     string str = "I come from China.";
//     for(int i = 0; i < str.length(); i++)
//         cout<<str[i];
//     cout<<endl;
//     cout<<senrev(str)<<endl;
    /*第5题*/
    string str = "gaaabbbbccddde";
    cout<<str<<endl;
    cout<<strzip(str)<<endl;
    
    //练习
    char s[50] = {0};
    char* who = "I";
    char* whom = "CSDN";
    sprintf(s, "%s love %s%d.", who, whom,123); //产生:"I love CSDN. "
    cout<<s<<endl;

    char a1[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
    char a2[] = {'H', 'I', 'J', 'K', 'L', 'M', 'N'};
//    sprintf(s, "%s%s", a1, a2); //Don't do that!
    //sprintf(s, "%.7s%.7s", a1, a2);//产生:"ABCDEFGHIJKLMN"

    sprintf(s, "%.6s%.5s", a1, a2);//产生:"ABCDEFHIJKL"
//     sprintf(s, "%.*s%.*s", sizeof(a1), a1, sizeof(a2), a2);
    cout<<s<<endl;


    return 0;  
}  



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值