非科班学习算法day9 | LeetCode151:反转字符串中的单词 ,卡码.右旋字符串,Leetcode28:实现strStr()
目录
介绍
包含LC的三道题目,还有相应概念的补充。
相关图解和更多版本:
代码随想录 (programmercarl.com)https://programmercarl.com/#%E6%9C%AC%E7%AB%99%E8%83%8C%E6%99%AF
一、基础概念补充:
1. erase函数
2.KMP算法
除了以上两个连接,还有大话数据结构相应部分可以阅读
二、LeetCode题目
1.LeetCode151: 反转字符串中的单词
题目链接:151. 反转字符串中的单词 - 力扣(LeetCode)
题目解析
分为两个步骤,首先新建一个函数用来移除多余空格;之后反转整个字符串,最后按照每个单词去反转。返回字符串s。(我写了一个我便于理解的版本 0v0)
c++代码如下:
class Solution {
public:
void deletekongge(string& s) {
// 删除多余空格
for (int i = s.size() - 1; i > 0; i--) {
// 删除多余空格
if (s[i] == ' ' && s[i - 1] == s[i]) {
s.erase(s.begin() + i);
}
}
// 删除头部空格
if (s.size() > 0 && s[0] == ' ') {
s.erase(s.begin());
}
if (s.size() > 0 && s[s.size() - 1] == ' ') {
s.erase(s.begin() + s.size() - 1);
}
}
string reverseWords(string s) {
deletekongge(s);
reverse(s.begin(), s.end());
int strat = 0;
for (int i = 0; i <= s.size(); ++i) {
if (s[i] == ' ' || i == s.size()) {
reverse(s.begin() + strat, s.begin() + i);
strat = i + 1;
}
}
return s;
}
};
注意点1:关于删除多余空格。我尝试过从前向后删除,但是会存在一个问题,就是删除一个元素,会导致后面元素的索引发生变化,而从后向前检索就不会存在这种状况。
注意点2:循环中负责的是:遇到两个重复的空格就进行删除操作。所以最后有可能会剩下开头和结尾的两个空格没有操作,所以要单独操作。
注意点3:最后的字符串内的单词有两种情况需要反转,一个是遇到空格,另一个是遍历结束,遇到空格,这里直接使用了reverse函数,所以遍历条件要更改为:i <= s.size()
注意点4:reverse函数内部的参数是引用形式,包括自己构建函数也要特别注意是不是需要引用形式传入。
2.卡码.右旋字符串
题目链接:55. 右旋字符串(第八期模拟笔试) (kamacoder.com)
题目解析
第一种思路就是先反转整个字符串,然后根据要求的长度,分别反转前后两部分字符串范围,直接返回;思路二是新建一个空间,使用append函数对字符串进行重新读取拼接。
思路一C++代码如下:
#include<iostream>
using namespace std;
#include<algorithm>
int main()
{
string s;
int k;
cin >> k;
cin >> s;
int len = s.size();
reverse(s.begin(), s.end());
reverse(s.begin(), s.begin() + k);
reverse(s.begin() + k , s.end());
cout << s << endl;
}
/**************************************************************
Problem: 1065
User: odCYZ6r27J3eZLOmW5Y2bc2N83vw [kamaCoder74837]
Language: C++
Result: 正确
Time:28 ms
Memory:2180 kb
****************************************************************/
思路二 c++代码如下:
#include<iostream>
using namespace std;
#include<algorithm>
int main()
{
string s;
int k;
cin >> k;
cin >> s;
int len = s.size();
string new_str = "";
for(int i = len - k; i < len; i++)
{
new_str.append(1,s[i]);
}
for(int i = 0; i < len - k; i++)
{
new_str.append(1,s[i]);
}
cout << new_str << endl;
return 0;
}
/**************************************************************
Problem: 1065
User: odCYZ6r27J3eZLOmW5Y2bc2N83vw [kamaCoder74837]
Language: C++
Result: 正确
Time:30 ms
Memory:2180 kb
****************************************************************/
3.Leetcode28:实现strStr
题目链接:28. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode)
题目解析
KMP算法的实现(我看了一下午),以下采用next数组减一写法。
C++代码如下:
class Solution {
public:
// 构建next数组
void getnext(int* next, const string& s) {
// 初始化.小技巧:j表示索引,也表示当前位置最长相等前后缀的长度
int j = -1;
next[0] = j;
// 处理前后缀不相等的情况
for (int i = 1; i < s.size(); i++) {
while (j >= 0 && s[j + 1] != s[i]) {
// 循环回退
j = next[j];
}
if (s[j + 1] == s[i]) {
// 向后移动i和j继续检查,但是i在外层循环已经定义了
j++;
}
next[i] = j;
}
}
// strStr
int strStr(string haystack, string needle) {
// 创建next数组
vector<int> next(needle.size());
// 获取str的next数组
getnext(&next[0], needle);
// 初始化
int j = -1;
// 根据next数组匹配两个字符串
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++;
}
// 如果j遍历结束
if (j == needle.size() - 1) {
// 此时文本串指针位置包含整个模式串的长度
return (i - needle.size() + 1);
}
}
// 匹配失败
return -1;
}
};
注意点1:j的初始化为-1的目的是为了满足我们的-1的需求,同时真正对比开始为什么i从1是因为此时第一个[0]元素没有比较的价值,已经被初始化为-1,所以直接从下一位的后缀的末尾开始,那不就是[1]么。
总结
KMP算法感觉相当复杂,后面还需要深入学习;关于字符串部分,个人认为i很多特别底层或者增加代码的部分,没有必要,所以写了自己好理解的版本,打卡第9天,坚持!!!