相关知识

  1. 对于一个字符串,如何在最后追加一个字符或多个相同字符或一个字符串?在这道题里我们用的是「+=」追加字符串,实际上还可以用append(),但要注意不能用push_back(),这个只能追加单个字符。

第一轮

第一版(0/20)

#include <cctype>
#include <iostream>
#include <vector>
using namespace std;

bool isDigitSubString(const string &a, const string &b){
    for (char c : a) {
        if(!isdigit(c)){
            return false;
        }
    }
    if (b.find(a) == string::npos) {
        return false;
    }

    return true;
}

int main() {
    string s;
    cin >> s;

    int l = 1;
    string longest_strs = "";
    for (int k = s.size(); k >= 1; k--) {
        for(int i = 0; i <= s.size() - k; i++){
            string temp = s.substr(i, k);
            if(isDigitSubString(temp, s)){
                l = k;
                longest_strs += temp;
                if(i == s.size() - 1){
                    cout << longest_strs << ',' << l << endl;
                    return 0;
                }
            }
        }
    }

    return 0;

}

  1. 最里层的分支结构不对。一个字符串,要先满足是数字子串,然后满足是最后一个子串,然后才可以输出,这个显然忽略了最后一个子串不是数字子串的情况。
  2. 我们把分支改成,首先判断当下框选住的子串是不是数字子串,是则更新,然后结束分支。然后判断当前有没有到框选住最后一个子串而且l == k(表明找到了数字子串),是则输出。

第二版(0/20)

#include <cctype>
#include <iostream>
#include <vector>
using namespace std;

bool isDigitSubString(const string& a, const string& b) {
    for (char c : a) {
        if (!isdigit(c)) {
            return false;
        }
    }
    if (b.find(a) == string::npos) {
        return false;
    }

    return true;
}

int main() {
    string s;
    cin >> s;

    int l = 1;
    string longest_strs = "";
    for (int k = s.size(); k >= 1; k--) {
        for (int i = 0; i <= s.size() - k; i++) {
            string temp = s.substr(i, k);
            if (isDigitSubString(temp, s)) {
                l = k;
                longest_strs += temp;
            }
            if (i == s.size() - 1 && l == k) {
                cout << longest_strs << ',' << l << endl;
                return 0;
            }
        }
    }

    return 0;

}

  1. 判断当前有没有到框选住最后一个子串而且l == k(表明找到了数字子串),是则输出。
  2. 上面这个逻辑是对的,但是这次改的时候,忽略了一个点——应该改为i == s.size() - k而非i == s.size() - 1

第三版(AC)

#include <cctype>
#include <iostream>
#include <vector>
using namespace std;

bool isDigitSubString(const string& a, const string& b) {
    for (char c : a) {
        if (!isdigit(c)) {
            return false;
        }
    }
    if (b.find(a) == string::npos) {
        return false;
    }

    return true;
}

int main() {
    string s;
    cin >> s;

    int l = 1;
    string longest_strs = "";
    for (int k = s.size(); k >= 1; k--) {
        for (int i = 0; i <= s.size() - k; i++) {
            string temp = s.substr(i, k);
            if (isDigitSubString(temp, s)) {
                l = k;
                longest_strs += temp;
            }
            if (i == s.size() - k && l == k) {
                cout << longest_strs << ',' << l << endl;
                return 0;
            }
        }
    }

    return 0;
}

  1. 这里还有一个值得注意的点,就是string longest_strs = ""这句初始化空串,不这么也行,因为默认就是空串。
  2. 但是,这样显示化地写出来,在检查错误的时候可以少费心思。
  3. 此外,当你要思考一个变量初始化的时候赋什么值的时候,对思考整个题目的逻辑是有帮助的。所以建议写一下。
  4. 另一个值得注意的知识点——longest_strs += temp;。我的串怎么跟到你这个串的屁股后面?就这么弄。

第二轮

第一版(AC)

#include <cctype>
#include <iostream>
#include <vector>
using namespace std;

bool isdigitstr(const string& s) {
    for (char c : s) {
        if (!isdigit(c)) return false;
    }

    return true;
}

int main() {
    string s;
    cin >> s;

    string result;
    int l = s.size() + 1;
    for (int k = s.size(); k >= 1; k--) {
        for (int i = 0; i <= s.size() - k; i++) {
            string str = s.substr(i, k);
            if (isdigitstr(str)){
                result += str;
                l = k;
            } 
            if (i == s.size() - k && l == k) {
                cout << result << ',' << l << endl;
                return 0;
            }
        }
    }
}

  1. 比起之前的一版,这一版在写函数的时候,只判断「传入字符串里的字符是不是全为数字」,不判断「传入的a是不是既是数字串又是b的子串」,因为后续的遍历逻辑已经限定了是在子串里找的,不必要把函数写得这么复杂。
  2. 这一版在写的时候,依然出现很多问题—— 比如最后判断i的停止位置是s.size() - k,其实一开始写的是s.size(),后来检查时想到那个「移动的方框」才意识到这个问题。再如两个选择语句最后是串联的,但实际上一开始还是往嵌套那个地方去写,只是因为之前好好思考过这个问题,留下的印象让笔者很快意识到此路不通。再比如最开始是没有l的,因为觉得直接输入k就行,但实际上l是用来辅助判断到此处要不要停下来输出并结束进程的,不引入l思路可能会很复杂。
  3. 尽管如此,这一轮做到了第一版就AC,仍然是一个非常大的进步。