程序员面试宝典-字符串中相同且长度最长子字符串及其位置

程序员面试宝典-字符串中相同且长度最长子字符串及其位置


字符串中相同且长度最长子字符串及其位置

题目

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

这个题目存在一个歧义,例如如果测试字符串为aaaaaa,我一开始以为结果是长度为3的aaa,原来正确答案是长度为5的aaaaa。即2个等长的子串可以有部分字符重叠。

第一种解法

原书中的题目是,可以重叠判断方式。
我没看懂书上的思路和代码实怎么对应的。这里根据代码的理解说一下他的思路。
这里是思路是从不同的位置开始截取不同长度的子字符串,然后分别正序和逆向寻找这个子字符串,
然后看找到这个字符串的位置是否相同,如果不同的话,则说明找到了一个满足的子字符串。

//书上的源代码,封装成函数形式,j的范围优化了一下,同时i的下限变成i>=1,其他不变    
pair<int, string> fun(const string &str)
{
    int count = 0;
    string substr, tep;
    int i, j, len = str.length();
    //i表示要截取的长度(1-len - 1) j表示开始截取的位置 并且j循环的判断条件是 j <= len - i
    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);//从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);
}

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;
    }
    return 0;
}

第二种解法

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

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;//表示i的下一个开始
    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++;//i自增 表示换用下一个字符作为结果子串的开头假设
            k = i + 1;
        }
        else 
        {    //若找到,则必有(j>=i+1)       

            s = i;//
            lt = 1;//统计子串字符的长度

            //从i的位置和j的位置同时开始往后判断 
            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;

    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值