第一版(有思路无实现)

#include <iostream>
#include <string>
using namespace std;

// 写一个函数来判断a是不是b的子串
bool isson(string &a, string &b){

}

int main() {
    // 获得输入
    string s, t;
    getline(cin, s);
    getline(cin, t);
   
    // 一种特殊情况:较短串即最长公共子串,可以从这个假设入手。
    if(s.size() <= t.size()){
        if (isson(s, t)) {
            cout << s;
        }else {
            // 如果较短串不是,那么优先在比较短串少一个字符的串里找,这样可以保证最长。
            // 分割字符串的时候只允许掐头去尾。
            // 一旦找到公共子串立即停止。
            // 为保证输出较短串中最先出现的子串,找子串时有优先掐尾,然后掐头。
        }
    }else {
        if (isson(t, s)) {
            cout << t;
        }else {
            // 同上。
        }        
    }

}
// 64 位输出请用 printf("%lld")
// 不需要找到全部公共子串,然后提取符合要求的最长公共子串,保证自己要找的最先出现即可。

  1. 笔者思路:
  2. 写一个判断a是否为b的子串的函数,便于调用。
  3. 从较短串入手,如果较短串是较长串的子串,则较短串就是最终结果,否则,长度减一继续判断。
  4. 长度减一分为掐头去尾两种情况,这里要优先去尾。这样会让先出现的子串成为最终结果。
  5. 先找全部公共子串的思路是麻烦的,但是暴力枚举在无奈时也可以作为备选方案。
  6. 智能反馈:
  7. 使用字符串的 find() 方法,可以检查某个串是否出现在另一个字符串中。
  8. 先检查较短串本身是否就是公共子串,再从较短串的最长子串(长度-1)开始检查,一步步减少长度。
  9. 对于每个长度,从左到右检查所有可能的子串,一旦找到这个长度下有公共子串,就记录并停止搜索该长度并结束。
  10. 通过上述两步,可以确保找到最长公共子串后会立即停止搜索。
  11. 笔者疑问:
  12. 写循环可以从字符串的下脚标入手,利用substr(s.begin(), s.end() - i)去尾,利用substr(s.begin() + i, s.end())掐头。
  13. 设较短串长度为n,假如长度为n-2,要分三种情况讨论,假如长度为n-3,要分4种情况讨论,那么如何用数学语言表示或者用库函数解决问题呢?
  14. 智能解答:
  15. C++ 的 string::substr(pos, len) 可以方便地提取子串,我们可以用双重循环​遍历所有可能的子串。​
  16. 外层循环​:遍历所有可能的子串长度 ​k​(从 ​n​ 递减到 ​1)​
  17. 内层循环​:遍历所有起始位置 ​i​(从 ​0​ 到 ​n - k)​检查子串是否存在​:用 longer.find(substr) != string::npos 判断是否在较长串中出现

第二版(编译错误)

#include <iostream>
#include <string>
using namespace std;

// 写一个函数来判断a是不是b的子串
bool isSubstring(string &a, string &b){
    return b.find(a) != string::npos;
}

int main() {
    // 获得输入
    string s, t;
    getline(cin, s);
    getline(cin, t);
   
    string shorter, longer;
    if(s.size() <= t.size()){
        shorter = s;
        longer = t;
    }else {
        shorter = t;
        longer = s;
    }

    for (int k = shorter.size(); k >= 1; k++) {
        for(int i = 0; i <= shorter.size() - k; i++){
            if (isSubstring(shorter.substr(i, k), longer)) {
                cout << shorter.substr(i, k);
                return 0; // 一旦找到直接返回
            }
        }
    }

}
// 64 位输出请用 printf("%lld")

  1. 编译有两个地方错误——
  2. 函数参数类型不匹配:笔者定义的函数要传入左值(已命名的变量),而调用的时候传入了临时对象(右值)。将函数参数改为 const 引用可以解决问题。
  3. 符号比较警告:shorter.size() 返回 size_t,是无符号类型。应统一类型解决问题。

第三版(0/20,运行超时)

#include <iostream>
#include <string>
using namespace std;

// 写一个函数来判断a是不是b的子串
bool isSubstring(const string &a, const string &b){
    return b.find(a) != string::npos;
}

int main() {
    // 获得输入
    string s, t;
    getline(cin, s);
    getline(cin, t);
   
    string shorter, longer;
    if(s.size() <= t.size()){
        shorter = s;
        longer = t;
    }else {
        shorter = t;
        longer = s;
    }

    for (int k = shorter.size(); k >= 1; k++) {
        for(int i = 0; i <= (int)shorter.size() - k; i++){
            if (isSubstring(shorter.substr(i, k), longer)) {
                cout << shorter.substr(i, k);
                return 0; // 一旦找到直接返回
            }
        }
    }

    return 0;
}
// 64 位输出请用 printf("%lld")

  1. 运行超时:程序未能在规定时间内运行结束,应检查是否循环有错或算法复杂度过大。
  2. 问题在于k是从大变小的,所以应该是k--而不是k++。

第四版(AC)

#include <iostream>
#include <string>
using namespace std;

// 写一个函数来判断a是不是b的子串
bool isSubstring(const string &a, const string &b){
    return b.find(a) != string::npos;
}

int main() {
    // 获得输入
    string s, t;
    getline(cin, s);
    getline(cin, t);
   
    string shorter, longer;
    if(s.size() <= t.size()){
        shorter = s;
        longer = t;
    }else {
        shorter = t;
        longer = s;
    }

    for (int k = shorter.size(); k >= 1; k--) {
        for(int i = 0; i <= (int)shorter.size() - k; i++){
            if (isSubstring(shorter.substr(i, k), longer)) {
                cout << shorter.substr(i, k);
                return 0; // 一旦找到直接返回
            }
        }
    }

    return 0;
}
// 64 位输出请用 printf("%lld")

  1. 做这道题有两个关键的参数i和k。如果把确定子串的矩形比喻成一个窗口,那么这两个参数分别是窗口的起始位置和横向长度。
  2. i负责移动窗口位置,k负责确定窗口长度。
  3. 其实,substr()这个函数也是通过这两个参数分割子串的。
  4. bool isSubstring(const string &a, const string &b) 函数中的参数是常引用。
  5. 既可以接受左值,也可以接受右值。
  6. 既有引用能避免拷贝字符串以提高性能,又有const能避免字符串在函数内被修改以保证安全。
  7. 常引用是处理只读字符串参数的推荐方式,尤其适合子串判断这类不修改输入的场景。