注意要点:
下面贴出代码:
class Solution {
public:
void reverseString(vector<char>& s) {
for (int i = 0; i < s.size() / 2; i++)
{
int tmp = s[i];
s[i] = s[s.size() - 1 - i];
s[s.size() - 1 - i] = tmp;
}
}
};
void reverseString(char* s, int sSize){
for (int i = 0; i < sSize / 2; i++)
{
int tmp = s[i];
s[i] = s[sSize - 1 - i];
s[sSize - 1 - i] = tmp;
}
}
注意要点:
下面贴出代码:
class Solution {
public:
string reverseStr(string s, int k) {
for (int i = 0; i < s.size(); i += 2 * k)
{
if (i + k <= s.size())
{
reverse(s.begin() + i, s.begin() + i + k);
}
else {reverse(s.begin() + i, s.end());}
}
return s;
}
};
char * reverseStr(char * s, int k){
int len = strlen(s);
for (int i = 0; i < len; i += 2 * k)
{
int right = fmin(i + k - 1, len - 1);
int left = i;
while (left < right)
{
char tmp = s[right];
s[right] = s[left];
s[left] = tmp;
left++;
right--;
}
}
return s;
}
注意要点:
下面贴出代码:
class Solution {
public:
string replaceSpace(string s) {
//统计空格数量
int count = 0;
for (int i = 0; i < s.size(); i++)
{
if (s[i] == ' ') {count++;}
}
//扩充为所需的数组大小
int oldSize = s.size();
s.resize(s.size() + 2 * count);
int newSize = s.size();
for (int i = newSize - 1, j = oldSize - 1; i >= 0, j >= 0; i--, j--)
{
if (s[j] == ' ')
{
s[i--] = '0';
s[i--] = '2';
s[i] = '%';
}
else {s[i] = s[j];}
}
return s;
}
};
char* replaceSpace(char* s){
int size = 0;
for (int i = 0; i < strlen(s); i++)
{
if (s[i] != ' ') {size++;}
else {size += 3;}
}
char* ans = (char* )malloc(sizeof(char) * (size + 1));
int ptr_s = strlen(s) - 1, ptr_ans = size;
ans[ptr_ans] = '\0';
ptr_ans--;
while (ptr_s >= 0)
{
if (s[ptr_s] != ' ')
{
ans[ptr_ans] = s[ptr_s];
ptr_s--;
ptr_ans--;
}
else
{
ans[ptr_ans] = '0';
ans[ptr_ans-1] = '2';
ans[ptr_ans-2] = '%';
ptr_ans -= 3;
ptr_s--;
}
}
return ans;
}
注意要点:
下面贴出代码:
class Solution {
public:
void myreverse(string& s, int start, int end)
{
int mid = start + (end - start) / 2;
for (int i = start; i < mid; i++)
{
swap(s[i], s[end - 1 - (i - start)]);
}
}
void removeExtraSpaces(string& s)
{
int slow = 0;
for (int i = 0; i < s.size(); i++)
{
if (s[i] != ' ')
{
if (slow) {s[slow++] = ' ';}
while (i < s.size() && s[i] != ' ') {s[slow++] = s[i++];}
}
}
s.resize(slow);
}
string reverseWords(string s) {
removeExtraSpaces(s);
myreverse(s, 0, s.size());
int start = 0;
for (int i = 0; i <= s.size(); i++)
{
if (i == s.size() || s[i] == ' ')
{
myreverse(s, start, i);
start = i + 1;
}
}
return s;
}
};
char * reverseWords(char * s){
int slow = 0;
for (int i = 0; i < strlen(s); i++)
{
if (s[i] != ' ')
{
if (slow) {s[slow++] = ' ';}
while (i < strlen(s) && s[i] != ' ') {s[slow++] = s[i++];}
}
}
s[slow] = '\0';
int left = 0, right = strlen(s) - 1; // 当前头部仍可能有空格时的字符串长度
while (left < right)
{
char tmp = s[right];
s[right] = s[left];
s[left] = tmp;
left++;
right--;
}
int len_tmp = strlen(s);
int len = strlen(s);
// 接下来翻转单词
int word_left = 0;
for (int i = 0; i < len + 1; i++)
{
if (s[i] == ' ' || s[i] == '\0')
{
int word_right = i - 1;
while (word_left < word_right)
{
char tmp = s[word_right];
s[word_right] = s[word_left];
s[word_left] = tmp;
word_left++;
word_right--;
}
word_left = i + 1;
}
}
return s;
}
注意要点:
下面贴出代码:
class Solution {
public:
string reverseLeftWords(string s, int n) {
reverse(s.begin(), s.end());
reverse(s.begin(), s.end() - n);
reverse(s.end() - n, s.end());
return s;
}
};
void reverse(char* s, int start, int end)
{
int left = start, right = end - 1;
while (left < right)
{
char tmp = s[left];
s[left] = s[right];
s[right] = tmp;
left++;
right--;
}
}
char* reverseLeftWords(char* s, int n){
reverse(s, 0, strlen(s));
reverse(s, 0, strlen(s) - n);
reverse(s, strlen(s) - n, strlen(s));
return s;
}
这不是代码随想录的分类方法,他的分类逻辑是根据题目讲解某种算法。但是这种算法我之前一刷完成后,只有在字符串这个章节中出现,但是却又非常重要(不会的话有些题直接很难做),所以单独开一个专题记录一下笔记。
KMP算法可以用作字符串匹配,当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了!所以如何记录已经匹配的文本内容,是KMP的重点,也是next数组肩负的重任。
next数组就是一个前缀表(prefix table)。
前缀表的定义:记录下标i之前(包括i)的字符串中,有多大长度的相同前缀后缀。
前缀表的作用:用来回退,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配。
也就是说,前缀表的任务是当前位置匹配失败,找到之前已经匹配上的位置,再重新匹配,此也意味着在某个字符失配时,前缀表会告诉你下一步匹配中,模式串应该跳到哪个位置。
文章中字符串的前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串。
后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串。
前缀表要求的就是相同前后缀的长度。
当前的搜索字符串的最长相等的前缀 和 后缀字符串是 子字符串aa ,因为找到了最长相等的前缀和后缀,匹配失败的位置是后缀子串的后面,那么我们找到与其相同的前缀的后面重新匹配就可以了。
所以前缀表具有告诉我们当前位置匹配失败,跳到之前已经匹配过的地方的能力。
next数组就可以是前缀表,但是很多实现都是把前缀表统一减一(右移一位,初始位置为-1)之后作为next数组。
其实这并不涉及到KMP的原理,而是具体实现,next数组既可以就是前缀表,也可以是前缀表统一减一(右移一位,初始位置为-1)。实际写代码的情况下,全部右移写起来简单很多,严格按照定义,写代码的时候就会有一些小细节容易忘记。
这里我就直接把带注释的代码拉过来了:
void getNext(int* next, const string& s){
int j = -1;
next[0] = j;
for(int i = 1; i < s.size(); i++) { // 注意i从1开始
while (j >= 0 && s[i] != s[j + 1]) { // 前后缀不相同了
j = next[j]; // 向前回退
}
if (s[i] == s[j + 1]) { // 找到相同的前后缀
j++;
}
next[i] = j; // 将j(前缀的长度)赋给next[i]
}
}
还是直接把代码拉过来,其中s是待匹配字符串,而t是模版字符串:
int j = -1; // 因为next数组里记录的起始位置为-1
for (int i = 0; i < s.size(); i++) { // 注意i就从0开始
while(j >= 0 && s[i] != t[j + 1]) { // 不匹配
j = next[j]; // j 寻找之前匹配的位置
}
if (s[i] == t[j + 1]) { // 匹配,j和i同时向后移动
j++; // i的增加在for循环里
}
if (j == (t.size() - 1) ) { // 文本串s里出现了模式串t
return (i - t.size() + 1);
}
}
注意要点:
下面贴出代码:
class Solution {
public:
void getNext(int* next, const string& s)
{
int j = -1;
next[0] = j;
for (int i = 1; i < s.size(); i++)
{
while (j >= 0 && s[i] != s[j + 1]) {j = next[j];}
if (s[i] == s[j + 1]) {j++;}
next[i] = j;
}
}
int strStr(string haystack, string needle) {
if (!needle.size()) {return 0;}
int next[needle.size()];
getNext(next, needle);
int j = -1;
for (int i = 0; i < haystack.size(); i++)
{
while (j >= 0 && haystack[i] != needle[j + 1]) {j = next[j];}
if (haystack[i] == needle[j + 1]) {j++;}
if (j == needle.size() - 1) {return i - (needle.size() - 1);}
}
return -1;
}
};
void getNext(int* next, const char* s)
{
int j = -1;
next[0] = j;
for (int i = 1; i < strlen(s); i++)
{
// 前后缀不同
while (j >= 0 && s[i] != s[j + 1]) {j = next[j];}
if (s[i] == s[j + 1]) {j++;}
next[i] = j;
}
}
int strStr(char * haystack, char * needle){
if (!strlen(needle)) {return 0;}
int next[strlen(needle)];
getNext(next, needle);
int j = -1;
for (int i = 0; i < strlen(haystack); i++)
{
while (j >= 0 && haystack[i] != needle[j + 1]) {j = next[j];}
if (haystack[i] == needle[j + 1]) {j++;}
if (j == strlen(needle) - 1)
{
return i - strlen(needle) + 1;
}
}
return -1;
}
注意要点:
下面贴出代码:
class Solution {
public:
void getNext (int* next, const string& s)
{
next[0] = -1;
int j = -1;
for(int i = 1;i < s.size(); i++)
{
while(j >= 0 && s[i] != s[j + 1]) {j = next[j];}
if(s[i] == s[j + 1]) {j++;}
next[i] = j;
}
}
bool repeatedSubstringPattern(string s) {
if (!s.size()) {return 0;}
int next[s.size()];
getNext(next, s);
int len = s.size();
if (next[len - 1] != -1 && !(len % (len - (next[len - 1] + 1)))) {return 1;}
return 0;
}
};
void getNext(int* next, const char* s)
{
int j = -1;
next[0] = j;
for (int i = 1; i < strlen(s); i++)
{
while (j >= 0 && s[i] != s[j + 1]) {j = next[j];}
if (s[i] == s[j + 1]) {j++;}
next[i] = j;
}
}
bool repeatedSubstringPattern(char * s){
int* next = (int* )malloc(sizeof(int) * strlen(s));
getNext(next, s);
int len = strlen(s);
if (next[len - 1] != -1 && !(len % (len - (next[len - 1] + 1)))) {return 1;}
return 0;
}