03.02.07 练习题目(第 04 天)
1. 0028. 找出字符串中第一个匹配项的下标
1.1 题目大意
描述:给定两个字符串 haystack
和 needle
。
要求:在 haystack
字符串中找出 needle
字符串出现的第一个位置(从 0
开始)。如果不存在,则返回 -1
。
说明:
- 当
needle
为空字符串时,返回0
。 - 1 ≤ h a y s t a c k . l e n g t h , n e e d l e . l e n g t h ≤ 1 0 4 1 \le haystack.length, needle.length \le 10^4 1≤haystack.length,needle.length≤104。
haystack
和needle
仅由小写英文字符组成。
示例:
输入:haystack = "hello", needle = "ll"
输出:2
解释:"sad" 在下标 0 和 6 处匹配。第一个匹配项的下标是 0 ,所以返回 0 。
输入:haystack = "leetcode", needle = "leeto"
输出:-1
解释:"leeto" 没有在 "leetcode" 中出现,所以返回 -1 。
我的答案:
//原始
class Solution {
public:
int strStr(string haystack, string needle) {
int m = haystack.size(),n = needle.size();
if(n > m) return -1;
int ans = INT_MAX;
for(int j = 0;j<m;++j){
if( haystack[j] == needle[0]){
bool issame = false;
for(int i = 0; i < n;++i){
if(haystack[j+i] == needle[i]) issame = true;
else {
issame = false;
break;
}
}
if(issame) return j;
// ans = ;
}
}
return -1;
}
};
//优化后:
class Solution {
public:
int strStr(string haystack, string needle) {
int m = haystack.size(), n = needle.size();
if (n == 0) return 0; // 如果 needle 为空,返回 0
if (n > m) return -1; // 如果 needle 比 haystack 长,返回 -1
for (int j = 0; j <= m - n; ++j) { // 只需要遍历到 haystack 中剩余的字符数大于等于 needle 的长度
if (haystack[j] == needle[0]) {
int i = 0;
while (i < n && haystack[j + i] == needle[i]) {
++i;
}
if (i == n) return j; // 如果找到完全匹配的子串,返回起始位置
}
}
return -1; // 如果没有找到匹配的子串,返回 -1
}
};
其他答案:
//KMP方法
class Solution {
public:
int strStr(string haystack, string needle) {
if (needle.empty()) return 0; // 如果needle为空,返回0
// 构建next数组
vector<int> next(needle.length());
int j = 0;
next[0] = 0; // next数组的第一个值总是0
for (int i = 1; i < needle.length(); ++i) {
while (j > 0 && needle[i] != needle[j]) {
j = next[j - 1]; // 如果不匹配,就向前移动j
}
if (needle[i] == needle[j]) {
j++; // 如果匹配,就增加j
}
next[i] = j; // 将j的值赋给next[i]
}
// 使用next数组进行KMP搜索
j = 0;
for (int i = 0; i < haystack.length(); ++i) {
while (j > 0 && haystack[i] != needle[j]) {
j = next[j - 1]; // 如果不匹配,就根据next数组移动模式串
}
if (haystack[i] == needle[j]) {
j++; // 如果匹配,就增加j
}
if (j == needle.length()) {
return i - j + 1; // 找到匹配,返回起始索引
}
}
return -1; // 没有找到匹配
}
};
心得:
- KMP算法
2. 0459. 重复的子字符串
2.1 题目大意
描述:给定一个非空的字符串 s
。
要求:检查该字符串 s
是否可以通过由它的一个子串重复多次构成。
说明:
- 1 ≤ s . l e n g t h ≤ 1 0 4 1 \le s.length \le 10^4 1≤s.length≤104。
s
由小写英文字母组成
示例:
输入: s = "abab"
输出: true
解释: 可由子串 "ab" 重复两次构成。
输入: s = "aba"
输出: false
我的答案:
class Solution {
public:
bool repeatedSubstringPattern(string s) {
string doubled = s + s;
string withoutFirstAndLast = doubled.substr(1, doubled.size() - 2);
return withoutFirstAndLast.find(s) != string::npos;
}
};
3. 0686. 重复叠加字符串匹配
3.1 题目大意
描述:给定两个字符串 a
和 b
。
要求:寻找重复叠加字符串 a
的最小次数,使得字符串 b
成为叠加后的字符串 a
的子串,如果不存在则返回 -1
。
说明:
- 字符串
"abc"
重复叠加0
次是""
,重复叠加1
次是"abc"
,重复叠加2
次是"abcabc"
。 - 1 ≤ a . l e n g t h ≤ 1 0 4 1 \le a.length \le 10^4 1≤a.length≤104。
- 1 ≤ b . l e n g t h ≤ 1 0 4 1 \le b.length \le 10^4 1≤b.length≤104。
a
和b
由小写英文字母组成。
示例:
输入:a = "abcd", b = "cdabcdab"
输出:3
解释:a 重复叠加三遍后为 "abcdabcdabcd", 此时 b 是其子串。
输入:a = "a", b = "aa"
输出:2
我的答案:
#include <string>
using namespace std;
class Solution {
public:
int repeatedStringMatch(string a, string b) {
// 计算最少需要重复的次数
int times = (b.length() + a.length() - 1) / a.length(); // 向上取整
// 构造重复 times 次的字符串
string repeated_a = "";
for (int i = 0; i < times; ++i) {
repeated_a += a;
}
// 检查 b 是否是 repeat_a 的子串
if (repeated_a.find(b) != string::npos) {
return times;
}
// 如果 b 不是 repeat_a 的子串,再尝试多重复一次
repeated_a += a;
if (repeated_a.find(b) != string::npos) {
return times + 1;
}
// 如果仍然不是子串,返回 -1
return -1;
}
};