还原原始字符串题解 | 豆包MarsCode AI刷题

146 阅读5分钟

题解

前置知识点

  1. 字符串操作

    • substr(start, length):从字符串中提取子串,start 是起始位置,length 是子串的长度。
    • size():返回字符串的长度。
  2. 动态数组(vector

    • vector<int> ne(n, 0):创建一个大小为 n 的整数向量,初始值为 0。
  3. 嵌套循环

    • 外层循环用于遍历字符串的每个位置。
    • 内层循环用于检查当前位置的子串是否与后续的子串匹配。
  4. 字符串匹配

    • 通过比较子串来判断是否存在重复模式。

代码思路

  1. 初始化

    • int n = s.size();:获取输入字符串的长度。
    • vector<int> ne(n, 0);:创建一个大小为 n 的向量 ne,用于存储每个位置的匹配长度。
  2. 计算匹配长度

    • 外层循环 for(int i = 0 ; i < n ; i ++):遍历字符串的每个位置。
    • 内层循环 for(int j = 0 ; j <= i ; j ++):检查从位置 j 开始的子串是否与后续的子串匹配。
    • int len = i - j + 1;:计算当前子串的长度。
    • if(n - i < len) continue;:如果剩余长度不足以匹配当前子串,跳过。
    • string suf = s.substr(j, len);:提取从位置 j 开始的子串。
    • string ns = s.substr(i + 1, len);:提取从位置 i + 1 开始的子串。
    • if(suf == ns):如果两个子串匹配,则记录匹配长度 ne[i] = len; 并跳出内层循环。
  3. 寻找最短初始字符串

    • string res = s;:初始化结果字符串为输入字符串。
    • 外层循环 for(int i = 0 ; i < n ; i ++):遍历字符串的每个位置。
    • int t = i;:初始化当前位置。
    • while(ne[t]) t = t + ne[t];:通过匹配长度跳转到下一个位置,直到没有匹配长度。
    • if(t == n - 1):如果跳转到最后一个位置,说明找到了最短初始字符串。
    • res = s.substr(0, i + 1);:更新结果字符串为当前位置之前的子串。
  4. 返回结果

    • return res;:返回最短初始字符串。

参考代码

std::string solution(const std::string& s) {
    int n = s.size();
    vector<int> ne(n, 0);
    for(int i = 0 ; i < n ; i ++) {
        for(int j = 0 ; j <= i ; j ++) {
            int len = i - j + 1;
            if(n - i < len) continue;
            string suf = s.substr(j, len);
            string ns = s.substr(i + 1, len);
            if(suf == ns) {
                ne[i] = len;
                break;
            }
        }
    }
    string res = s;
    for(int i = 0 ; i < n ; i ++) {
        int t = i;
        while(ne[t]) t = t + ne[t];
        if(t == n - 1) {
            res = s.substr(0, i + 1);
            break;
        }
    }
    return res;
}

总结

通过计算每个位置的匹配长度,并利用这些匹配长度来寻找最短的初始字符串。这种方法通过嵌套循环和字符串匹配来实现,确保了在复杂度允许的范围内找到最短初始字符串。

更多 string 类型常用方法

1. 构造函数

  • std::string():默认构造函数,创建一个空字符串。
  • std::string(const char* s):从 C 风格字符串构造一个 std::string
  • std::string(const std::string& str):拷贝构造函数,从另一个 std::string 构造一个 std::string
  • std::string(const std::string& str, size_t pos, size_t len = npos):从 str 的 pos 位置开始,拷贝 len 个字符构造一个 std::string

2. 字符串长度和容量

  • size() 或 length():返回字符串的长度。
  • empty():检查字符串是否为空。
  • capacity():返回当前分配的存储空间大小。
  • reserve(size_t n):为字符串预留至少 n 个字符的存储空间。
  • resize(size_t n, char c = '\0'):调整字符串的大小为 n,如果新大小大于当前大小,则用字符 c 填充。

3. 访问字符

  • operator[](size_t pos):访问字符串中位置 pos 处的字符。
  • at(size_t pos):访问字符串中位置 pos 处的字符,并进行边界检查。
  • front():返回字符串的第一个字符。
  • back():返回字符串的最后一个字符。

4. 字符串修改

  • operator+=(const std::string& str):将 str 追加到当前字符串。
  • append(const std::string& str):将 str 追加到当前字符串。
  • push_back(char c):在字符串末尾添加一个字符 c
  • assign(const std::string& str):将当前字符串赋值为 str
  • insert(size_t pos, const std::string& str):在位置 pos 处插入 str
  • erase(size_t pos = 0, size_t len = npos):从位置 pos 开始删除 len 个字符。
  • replace(size_t pos, size_t len, const std::string& str):从位置 pos 开始,用 str 替换 len 个字符。
  • clear():清空字符串。

5. 字符串查找

  • find(const std::string& str, size_t pos = 0):从位置 pos 开始查找 str,返回第一次出现的位置。
  • rfind(const std::string& str, size_t pos = npos):从位置 pos 开始反向查找 str,返回第一次出现的位置。
  • find_first_of(const std::string& str, size_t pos = 0):从位置 pos 开始查找 str 中的任意字符,返回第一次出现的位置。
  • find_last_of(const std::string& str, size_t pos = npos):从位置 pos 开始反向查找 str 中的任意字符,返回第一次出现的位置。
  • find_first_not_of(const std::string& str, size_t pos = 0):从位置 pos 开始查找不在 str 中的任意字符,返回第一次出现的位置。
  • find_last_not_of(const std::string& str, size_t pos = npos):从位置 pos 开始反向查找不在 str 中的任意字符,返回第一次出现的位置。

6. 子字符串

  • substr(size_t pos = 0, size_t len = npos):返回从位置 pos 开始,长度为 len 的子字符串。

7. 字符串比较

  • compare(const std::string& str):比较当前字符串与 str,返回一个整数,表示比较结果(0 表示相等,正数表示当前字符串大于 str,负数表示当前字符串小于 str)。

8. 字符串转换

  • c_str():返回一个指向 C 风格字符串的指针(以 null 结尾的字符数组)。
  • data():返回一个指向字符串数据的指针(不一定是 null 结尾)。