求字符串中相同且长度最长的字符串及其首字母的位置

题目:输入一行字符串,找出其中出现的相同且长度最长的字符串,输出它及首字符的位置。例如“yyabcdabjcabceg”,输出结果应该为abc和3。


解法1:

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

       以abcab为例子分析如下:

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

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

       最后寻找长度为2的子串,首先是ab,用find函数返回在abcab中正序查找的位置0,用rfind函数返回在abcab中逆序查找的位置3。这两个位置不相等,说明在不同的位置存在相同的子串ab。直接输出ab:1,然后退出程序。

详细代码见《程序员面试宝典》(第三版) P226页  面试例题2

//求一个字符串中出现的相同且长度最长的字符串
pair<string, int> func2(string str)
{
	string strTemp;
	int i, j;
	int iLen = str.length();
	for (i = 0; i < iLen; i++)
	{
		for (j = iLen; j > 1; j--)  //从每个后缀的最长子串开始
		{
			if (i + j <= iLen)  //确保获取子串不会越界
			{
				size_t pos1, pos2;
				strTemp = str.substr(i, j);
				pos1 = str.find(strTemp);
				pos2 = str.rfind(strTemp);
				if (pos1 != pos2)  //位置不一致则说明存在重复子串
				{
					return make_pair(strTemp, pos1 + 1);
				}
			}
		}
	}
	return make_pair("", -1);
}


附:

这个题目存在一个歧义,例如如果测试字符串为aaaaaa,我一开始以为结果是长度为3的aaa,原来正确答案是长度为5的aaaaa。即2个等长的子串可以有部分字符重叠。因此,面试前最好问仔细点题目意图,免得自己把自己给坑了。

       首先,这题的2个for循环中的那个if语句明显多于,这个if语句可以放到j的for循环中去,  即for(int j=0;j<str.length();j++)改为for(int j=0;j<=str.length()-i;j++)。

       再者,书上给的程序有一个小bug,例如输入测试例子abba,没有任何输出结果,理论上应该输出a:1或者b:2。当测试例子为abca,也没有任何输出结果,理论上应该输出a:1。 这是因为寻找相同的子串时,程序忽略了长度为1的子串,当然这也可能是题目本意。如果不忽略长度为1的子串,直接修改i变量的下限,令for中的i>=1即可。


解法2:

       这道题目和前面的面试例题1非常相似,因此两者的思想也相似,法二的代码也是在面试例题1的方法二的代码基础上稍作修改。

       相同子串的首字符必定相等,因此依次遍历str的每个字符作为相等子串的首字符,然后在str中搜索与首字符相等的字符,然后从这两个相等的首字符开始,依次比较下一个字符是否相等,相等的话字符长度就会增加,直到下一个字符不等为止或者到了字符串的末尾。然后把这长度最大的值存放在maxlen中,最后返回长度最大的子串和起始字符的下标。

       程序源代码如下,fun函数是书上的源代码,封装成函数形式,去掉if语句后j的范围优化为j<=len-i,同时i的下限变成i>=1,其他不变。fun1是法二的版本。

#include<iostream>            
#include<string>   
using namespace std;   
  
//书上的源代码,封装成函数形式,j的范围优化了一下,同时i的下限变成i>=1,其他不变  
pair<int,string> fun(const string &str)    
{    
    int count=0;    
    string substr,tep;    
    int i,j,len=str.length();    
    for(i=len-1;i>=1;--i){    
        for(j=0;j<=len-i;j++){    
                size_t t=0;    
                size_t num=0;    
                tep=str.substr(j,i);    
                t=str.find(tep);    
                num=str.rfind(tep);    
                if(t!=num){    
                    count=t+1;    
                    substr=tep;    
                    return make_pair(count,substr);    
                }     
        }    
    }    
    return make_pair(count,substr);    
}    
        
        
pair<int,string> fun1(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);    
}    
        
int main()    
{    
            
    string str;    
    pair<int,string> rs;    
    while(cin>>str)    
    {    
        rs=fun(str);    
        cout<<rs.second<<":"<<rs.first<<endl;    
        rs=fun1(str);    
        cout<<rs.second<<":"<<rs.first<<endl;    
        
    /*书上源代码   
    int count=0;  
        string substr,tep;  
        int i,j,len=str.length();  
        for(i=len-1;i>1;--i){  
            for(j=0;j<len;j++){  
                if(j+i<=len){  
                    size_t t=0;  
                    size_t num=0;  
                    tep=str.substr(j,i);  
                    t=str.find(tep);  
                    num=str.rfind(tep);  
                    if(t!=num){  
                        count=t+1;  
                        substr=tep;  
                        cout<<tep<<" : "<<t+1<<endl;  
                        return 0;  
                    }  
                }  
            }  
        }*/    
                
        
    }    
    return 0;    
}  



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值