题解
前置知识点
-
字符串操作:
substr(start, length):从字符串中提取子串,start是起始位置,length是子串的长度。size():返回字符串的长度。
-
动态数组(
vector) :vector<int> ne(n, 0):创建一个大小为n的整数向量,初始值为 0。
-
嵌套循环:
- 外层循环用于遍历字符串的每个位置。
- 内层循环用于检查当前位置的子串是否与后续的子串匹配。
-
字符串匹配:
- 通过比较子串来判断是否存在重复模式。
代码思路
-
初始化:
int n = s.size();:获取输入字符串的长度。vector<int> ne(n, 0);:创建一个大小为n的向量ne,用于存储每个位置的匹配长度。
-
计算匹配长度:
- 外层循环
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;并跳出内层循环。
- 外层循环
-
寻找最短初始字符串:
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);:更新结果字符串为当前位置之前的子串。
-
返回结果:
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 结尾)。