文章目录
字符串
`
一、反转
1.1 (344)反转字符串
反转字符串s
reverse(s.begin(),s.end());//第1种
//第二种、第三种
for(int i=0,j=s.size()-1;i<=j;i++,j--)
{
//swap(s[i],s[j]);//第2种
char temp=s[i];//第3种
s[i]=s[j];
s[j]=temp;
}
1.2(541) 反转特定地方的字符串
给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
输入:s = “abcdefg”, k = 2
输出:“bacdfeg”
其实在遍历字符串的过程中,只要让 i += (2 * k),i 每次移动 2 * k 就可以了,然后判断是否需要有反转的区间。
因为要找的也就是每2 * k 区间的起点,这样写,程序会高效很多。通过for循环的变量+2*k来控制反转起始点,再加k控制反转结束点
有reverse和自己写的反转函数两种写法,reverse速度更快,内存占用量也少。
reverse函数功能是逆序(或反转),多用于字符串、数组、容器。头文件是#include
reverse函数用于反转在[first,last)范围内的顺序(包括first指向的元素,不包括last指向的元素),reverse函数无返回值
是一个左闭右开区间函数,因为字符串也是一种数组,所以元素在内存中是连续分布,所以可以直接通过指针加加控制指向
void fanzhuan(string & s,int start,int end)
{
for(int i=start,j=end;i<=j;i++,j--)
{
swap(s[i],s[j]);
}
}
string reverseStr(string s, int k)
{
for(int i=0;i<s.size();i+=2*k)
{
if(i+k<=s.size())
{
//fanzhuan(s,i,i+k-1);//法1
reverse(s.begin()+i,s.begin()+i+k );
}
else
{
//fanzhuan(s,i,s.size()-1);//法1
reverse(s.begin()+i,s.end() );
}
}
return s;
1.3(剑指offer05) 特定字符替换空格
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
示例 1:输入:s = “We are happy.” 输出:“We%20are%20happy.”
resize:
改变容器的大小,使得其包含n个元素。
myvector.resize(5);
myvector.resize(8,100);
myvector.resize(12);
常见三种用法。
1、如果n小于当前的容器大小,那么则保留容器的前n个元素,去除(erasing)超过的部分。
2、如果n大于当前的容器大小,则通过在容器结尾插入(inserting)适合数量的元素使得整个容器大小达到n。且如果给出val,插入的新元素全为val,否则,执行默认构造函数。
3、如果n大于当前容器的容量(capacity)时,则会自动重新分配一个存储空间。
class Solution {
public:
string replaceSpace(string s) {
int count = 0; // 统计空格的个数
int sOldSize = s.size();
for (int i = 0; i < s.size(); i++) {
if (s[i] == ' ') {
count++;
}
}
// 扩充字符串s的大小,也就是每个空格替换成"%20"之后的大小
s.resize(s.size() + count * 2);
int sNewSize = s.size();
// 从后先前将空格替换为"%20"
for (int i = sNewSize - 1, j = sOldSize - 1; j < i; i--, j--) {
if (s[j] != ' ') {
s[i] = s[j];
} else {
s[i] = '0';
s[i - 1] = '2';
s[i - 2] = '%';
i -= 2;
}
}
return s;
}
};
1.4 (151)反转字符串里的单词
给定一个字符串,逐个翻转字符串中的每个单词。 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
示例 1:
输入: “the sky is blue”
输出: “blue is sky the”
第一步考虑肯定是减去空格:
先减去多个空格,直至每个间隔的空格数只有一个;然后再减去首尾两个空格;再进行翻转,先对字符串整体进行翻转,再对字符串里的单词进行反转
string reverseWords(string s)
{
//1、减去多余空格
for(int i=s.size()-1;i>0;i--)
{
if(s[i]==s[i-1]&& s[i]==' ')
s.erase(s.begin()+i);
}
//2减去首尾空格
if(s[0]==' ') s.erase(s.begin());
if(s.size()>0 && s[s.size()-1]==' ') s.erase(s.begin()+s.size()-1);
//反转
reverse(s.begin(),s.end());//全部反转
for(int i=0;i<s.size();i++)
{
int j=i;
while(j<s.size()&& s[j]!=' ')
{
j++;
}//j此时在空格的位置
reverse(s.begin()+i,s.begin()+j);//reverse左闭右开
i=j;//因为i还要在循环中加一,所以就令i=j;
}
return s;
}
1.5 (剑指58)左旋字符串
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
为了让本题更有意义,提升一下本题难度:不能申请额外空间,只能在本串上操作。
本题则是先局部反转再 整体反转
class Solution {
public:
void reversse(string & s,int str,int end)
{
for(int i=str,j=end;i<j;i++,j--)
{
char temp=s[i];
s[i]=s[j];
s[j]=temp;
}
}
string reverseLeftWords(string s, int n) {
//法1
//string str1=s.substr(0,n);
// string str2=s.substr(n,size(s)-n);
// s=str2+str1;
//法2
reversse(s,0,n-1);
reversse(s,n,s.size()-1);
reversse(s,0,s.size()-1);
return s;
}
};
1.6总结
普通反转字符串,可以用reverse,但是记住是左闭右开,或者是for循环里swap函数;
当需要固定规律一段一段地去处理字符串,要在for循环中做文章。
发现先整体反转再局部反转 是一个很妙的思路,要在反转时学会应用。
说到字符串反转就要想到reverse,swap.是整体反转还是局部反转?或是二者结合。
二、KMP算法
1.KMP算法基础部分
KMP的经典思想是:当出现字符串不匹配时,可以记录一部分之前已经匹配的文本内容,利用这些信息避免从头再去做匹配。
KMP主要应用在字符串匹配上。KMP的主要思想是当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。
如何记录已经匹配的文本内容,是KMP的重点,也是next数组肩负的重任。
next数组就是一个前缀表(prefix table)。
前缀表有什么作用呢?
前缀表是用来回退的,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配。
2.KMP例题
(28)、实现 strStr() 函数。
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。
class Solution {
public:
int strStr(string haystack, string needle) {
//法1:
return haystack.find(needle);
//法二:KMP算法
int m=haystack.size();
int n=needle.size();
if (n==0) return 0;
vector<int> next(n,0);
//求next数组(针对模式串而言)
for(int i=1,j=0;i<n;i++)
{
while(j>0 && needle[i]!=needle[j])
//needle[i] != needle[j],找上一个匹配串子串的开始匹配的位置
{
j=next[j-1];
}
if(needle[i]==needle[j])
//needle[i] == needle[j],匹配串子串长度增加1。
{
j++;
}
next[i]=j;
}
//匹配(针对主串而言)
for(int i=0,j=0;i<m;i++)
{
while(j>0 && haystack[i]!=needle[j])
//haystack[i] != needle[j],利用next更新匹配串子串的开始匹配的位置
{
j=next[j-1];
}
if(haystack[i]==needle[j])//haystack[i] == needle[j], 匹配串子串长度增加1
{
j++;
}
if(j==n)
{
return i-n+1;
}
return -1;
}
}
};
(459)
给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。
输入: s = “abab”
输出: true
解释: 可由子串 “ab” 重复两次构成。
输入: s = “aba”
输出: false
s的长度为len
重点是如果next[len-1]不为0,就说明有最长公共前后缀,可能是重复串。再去判断len%(next[len-1])==0;若为0,则为重复串
class Solution {
public:
bool repeatedSubstringPattern(string s) {
int m=s.size();
vector<int> next(m,0);
//求next数组
for(int j=0,i=1;i<m;i++)
{
while(j>0 && s[i]!=s[j])
{
j=next[j-1];
}
if(s[i]==s[j])
{
j++;
}
next[i]=j;
}
//
// if(m%(m-next[m-1])==0)
//这样不对,还必须保证next[m-1]!=0
if(next[m-1]!=0 && m%(m-next[m-1])==0)
{
return true;
}
return false;
}
};
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。