代码随想录day9字符串2

翻转字符串里的单词

题目链接
文章讲解

AC

主要思路是去空格然后保存在vector 里面。

class Solution {
public:
    string reverseWords(string s) {
        vector<string> v;
        string h="";
        string ans="";
        for(int i=0;i<s.size();i++)
        {
              while(s[i]==' '&&i<s.size())//处理前面空格
            {
               i++;
            }
            h+=s[i];
            if(i+1<s.size()){  // 要用i+1一定要先判断
            if(s[i+1]==' ')
            {
                v.push_back(h);
                h="";
                 while(s[i+1]==' '&&i<s.size()) i++; //处理中间和末尾空格
            }
            }
        }
       if(h.size()>0) v.push_back(h);
        string res="";
       
        for(int i=v.size()-1;i>=0;i--)
        {
            if(i==0)  res+=v[i];
            else res+=v[i]+" ";
        }
        return res;
    }
};

C++中的substr()函数详解

在C ++中,substr()是用于字符串处理的预定义函数。string.h是字符串函数所需的头文件。

此函数将两个值pos和len作为参数,并返回一个新构造的字符串对象,其值初始化为该对象的子字符串的副本。从pos开始复制字符串,直到pos + len表示[pos,pos + len)为止。

重要事项:

第一个字符的索引为0(不是1)。

如果pos等于字符串长度,则该函数返回一个空字符串。

如果pos大于字符串长度,则抛出out_of_range。如果发生这种情况,则字符串中没有任何更改。

如果对于所请求的子字符串len大于字符串的大小,则返回的子字符串为[pos,size())。

句法:

字符串substr(size_t pos,size_t len)const;

参数:

pos:要复制的第一个字符的位置。len:子字符串的长度。size_t:这是一个无符号整数类型。返回值:返回一个字符串对象。
在这里插入图片描述
输出:字符串是:ook

右旋字符串

题目链接
文章讲解

AC

一种用substr,一种用for字符串拼接 见代码和代码注释部分

#include <iostream>
#include <cstdio>
#include <fstream>
#include <iomanip>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include<list>
#include <set>
#include <ctime>
#include<unordered_map>
#include <bitset>
#include<random>
#include<regex>
#include <chrono>
#include<unordered_map>
#include<unordered_set>
using namespace std;

typedef long long ll;
#define pr pair<double,int>
#define tp tuple<int,int,int>
const int N = 2e6 + 7;
const int mod = 998244353;
ll a[N],s[N];
ll n, m, k;
ll e[N];
ll ne[N];
ll head,idx;

void solve()
{
    int k;
    string s;
    cin>>k>>s;
    string x="";
    string i=s.substr(s.size()-k,k);
    string j=s.substr(0,s.size()-k);
    x=i+j;
    // for(int i=s.size()-k;i<s.size();i++)
    // x+=s[i];
    // for(int i=0;i<s.size()-k;i++) x+=s[i];
    cout<<x;

}

 int main()
{
    cin.tie(0); 
    cout.tie(0);
    ios::sync_with_stdio(false);//提高cin、cout的输入输出效率
    solve();
}

KMP算法总结

算法思想

KMP算法(Knuth-Morris-Pratt算法)是一种高效的字符串匹配算法,用于在主串中查找模式串出现的位置。其核心思想是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数。

核心概念

部分匹配表(Partial Match Table):也称为next数组,记录模式串前缀和后缀的最长公共元素长度

失配处理:当字符不匹配时,根据next数组回溯模式串的位置,避免重新匹配已匹配的部分

算法步骤

  1. 构建next数组(预处理模式串)
// 0-indexed实现
ne[0] = -1;
for (ll i = 1, j = -1; i < n; i++) {
    while (j >= 0 && p[i] != p[j + 1]) j = ne[j];
    if (p[i] == p[j + 1]) j++;
    ne[i] = j;
}

// 1-indexed实现
for (ll i = 2, j = 0; i <= n; i++) {
    while (j && p[i] != p[j + 1]) j = ne[j];
    if (p[i] == p[j + 1]) j++;
    ne[i] = j;
}
  1. 使用next数组进行匹配
// 0-indexed实现
for (ll i = 0, j = -1; i < m; i++) {
    while (j >= 0 && s[i] != p[j + 1]) j = ne[j];
    if (s[i] == p[j + 1]) j++;
    if (j == n - 1) {
        cout << i - n + 1 << " ";
        j = ne[j];
    }
}

// 1-indexed实现
for (ll i = 1, j = 0; i <= m; i++) {
    while (j && s[i] != p[j + 1]) j = ne[j];
    if (s[i] == p[j + 1]) j++;
    if (j == n) {
        cout << i - n << " ";
        j = ne[j];
    }
}

两种实现方式对比

在这里插入图片描述

关键点解析

next数组作用:

记录模式串的最长相同前后缀长度

当匹配失败时,指示模式串指针应该回溯的位置

匹配过程:

主串指针i只增不减,一直向前移动

模式串指针j根据匹配情况在next数组指导下回溯

当j达到模式串长度时表示匹配成功

时间复杂度:

构建next数组:O(n)

匹配过程:O(m)

总时间复杂度:O(n+m)

题目链接

#include <iostream>
#include <cstdio>
#include <fstream>
#include <iomanip>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include<list>
#include <set>
#include <ctime>
#include<unordered_map>
#include <bitset>
#include<random>
#include<regex>
#include <chrono>
#include<unordered_map>
#include<unordered_set>
using namespace std;

typedef long long ll;
#define pr pair<double,int>
#define tp tuple<int,int,int>
const int N = 1e6 + 7;
const int mod = 998244353;
char s[N],p[N];//s是模式串,p是主串
ll ne[N];
void solve()
{
   ll n,m;
   cin>>n>>p+1>>m>>s+1;
   //匹配成功的
    for(ll i=2,j=0;i<=n;i++)
    {
        while(j&&p[i]!=p[j+1]) j=ne[j];
        if(p[i]==p[j+1]) j++;
        ne[i]=j;
    }

   for(ll i=1,j=0;i<=m;i++)
   {
    while(j&&s[i]!=p[j+1]) j=ne[j];
    if(s[i]==p[j+1]) j++;
    if(j==n)
    {
        cout<<i-n<<" ";
        j=ne[j];
    }
   }
}

 int main()
{
    cin.tie(0); 
    cout.tie(0);
    ios::sync_with_stdio(false);//提高cin、cout的输入输出效率
    solve();
}

实现 strStr()

题目链接
文章讲解

AC

find:

class Solution {
public:
    int strStr(string haystack, string needle) {
         return haystack.find(needle);
    }
};

kmp:

class Solution {
public:
    int strStr(string haystack, string needle) {
         int n=needle.size();
         int m=haystack.size();
         const int N=1e5;
         int ne[N];
         memset(ne,0,sizeof(ne));
         ne[0]=-1;
         //求匹配表
         for(int i=1,j=-1;i<n;i++)
         {
            while(j>=0&&needle[j+1]!=needle[i]) j=ne[j];
            if(needle[j+1]==needle[i]) j++;
            ne[i]=j;
         }
         //匹配成功
         for(int i=0,j=-1;i<m;i++)
         {
             while(j>=0&&needle[j+1]!=haystack[i]) j=ne[j];
            if(needle[j+1]==haystack[i]) j++;
            if(j==n-1)
            {
                return i-j;
                j=ne[j];
            }
         }
         return -1;
    }
};

重复的子字符串

题目链接
文章讲解

AC

KMP做法:

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        int n=s.size();
        const int N=1e4+5;
        int ne[N];
        memset(ne,0,sizeof(N));
        ne[0]=-1;
        for(int i=1,j=-1;i<n;i++)
        {
            while(j>=0&&s[i]!=s[j+1]) j=ne[j];
            if(s[i]==s[j+1]) j++;
            ne[i]=j;
        }
        if(n%(n-(ne[n-1]+1))==0&&ne[n-1]!=-1) return true;
        else return false;
        
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值