字符串

字符串

1、反转字符串

要求:反转一个字符串,但是不能创建新的字符串。

**思路:**定义一个头尾指针,不断交换。

伪代码:

len = str.size();
for(i = 0, j = len - 1; i < j; i++,j--)
{
    swap(str(i),str(j));
}

2、反转字符串Ⅱ

​ 给一个字符串,把每 2 k 2k 2k段里的前 k k k个字符串进行反转,如果最后一段不够 2 k 2k 2k,那么就反转 k k k个,如果 k k k也不够,那么就全反转。

​ 如: k = 3 k=3 k=3 a b c g e f g z abcgefgz abcgefgz,输出为 c b a g e f z g cbagefzg cbagefzg

伪代码:

for(i = 0; i < str.size; i = i+2k)
{
    if(i+k <= str.size)
    {
        reverse(str, i , i+k)
        continue;
    }
    reverse(str,i,str.size);
}

3、反转字符串里的单词

要求: 空格空格hello world 空格空格翻转为 world hello 并删除空格。

**思路:**先直接删除多余的空格,把整个字符串全部翻转,然后在把每一个单词里面的字符全翻转。

**伪代码:**使用双指针,类似于移除数组元素的思路移除空格。然后在翻转全部字符串,在根据单词之间空格的位置翻转单词。

#include
#include
using namespace std;
void reverse(string& s, int start, int end) 
{
    for (int i = start, j = end; i < j; i++, j--) 
    {
        swap(s[i], s[j]);
    }
}
int main(void)
{
    string str = "  hello   world  l  ";
    int slow_index = 0;
    int fast_index = 0;
    while(str[fast_index] == ' ' && fast_index < str.size())  fast_index++;
    for(;fast_index < str.size();fast_index++)
    {

        if(str[fast_index] == str[fast_index-1] && str[fast_index] == ' ' && fast_index > 1)
            continue;
        else
        {
                str[slow_index++] = str[fast_index];
        }

        //slow_index++;
    }
    str.resize(slow_index);//设置字符串占据的空间大小
    reverse(str,0,str.size()-1);
    cout << str << endl;
    int temp = 0;
    for(int i = 0;i < str.size();++i)
    {
        if(str[i] == ' ')
        {
            reverse(str,temp,i-1);
            temp = i + 1;
        }       
    }
    reverse(str,temp,str.size()-1);
    cout << str << endl;
    return 0;
}

4、KMP算法理论基础

KMP算法解决的就是字符串匹配的问题:给出一个字符串aabaabaaf,在给出一个模式串:aabaaf。

前缀与后缀:

前缀是包含首字母,不包含尾字母的所有子串。如aabaaf的前缀有a,aa,aab,aaba,aabaa,后缀是包含尾字母但是不包含首字母的所有字符串,aabaaf的后缀有f,af,aaf,baaf,abaaf。

最长相等前后缀:

a的最长相等前后缀就0,aa的最长相等前后缀为1,aab的最长相等前后缀为0,aaba的最长相等前后缀为1,aabaa的最长相等前后缀为2,aabaaf的最长相等前后缀为0,那么他的前缀表就是010120。

使用前缀表进行匹配:

对aabaabaaf用模式串aabaaf进行匹配时,匹配到字母f时失效,已经匹配过的字符串为aabaa,他的最长相等前后缀为2,所有要跳到2来开始进行匹配。因为相等前后缀的性质。

next数组:

next数组中放的是前缀表。

5、KMP算法的实现

next数组初始化:

初始化→前后缀不相同→前后缀相同→更新

//定义i指向后缀末尾位置,j指向前缀末尾位置
j = 0; next[0] = 0;
for(i=1;i<s.size();i++)
{
    while(s[i] != s[j] && j > 0)//这里不能写成if,因为回退是一个连续回退的过程
    {
        j = next[j-1];
    }
    if(s[i] == s[j])
    {
        j++;
        next[i] = j;
    }
}

6、重复子串

要求:给一个字符串,看这个字符串是不是由重复的字符串组成的

**思路(移除匹配):**如果一个字符串abcabc,确定其是由重复字符串组成的。即:

str = "abcabc";
temp1 = str.size()/2;
str = "abcabc" + "abcabc";//如果把由重复字符串组成的字符串,那么这样拼接起来,str1的后半部分和str2的
//前半部分组成的字符串必然和原字符串一样
str = str[1:str.size()-2];//去掉第一个字母和第2个字母
return str.find();

**思路(KMP算法):**最小重复子串就是最长相等前后缀不包含的子串

如果len % (len - (next[len - 1] + 1)) == 0 ,则说明数组的长度正好可以被 (数组长度-最长相等前后缀的长度) 整除 ,说明该字符串有重复的子字符串。

数组长度减去最长相同前后缀的长度相当于是第一个周期的长度,也就是一个周期的长度,如果这个周期可以被整除,就说明整个数组就是这个周期的循环。

    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() == 0) {
            return false;
        }
        int next[s.size()];
        getNext(next, s);
        int len = s.size();
        if (next[len - 1] != -1 && len % (len - (next[len - 1] + 1)) == 0) {
            return true;
        }
        return false;
    }

你可能感兴趣的:(c语言,c++算法刷题笔记,代码随想录,算法,数据结构)