代码随想录训练营day9|151.翻转字符串里的单词,右旋字符串,28. 实现 strStr(),459.重复的子字符串

151.翻转字符串里的单词

思路

1.先将多余空格去除。
2.翻转整个字符串。
3.对单词逐一翻转。
1:

int fast=0,slow=0,end=s.size()-1;
while(s[fast]==' ')
     fast++;
 while(s[end]==' ')
     end--;//可以先将首尾的空格去除
 for(;fast<=end;fast++){
     while(fast<=end&&s[fast]==' '&&s[fast-1]==' ')//确保如果有连续多个空格,只填一个
         fast++;
     s[slow++]=s[fast];
 }
 s.resize(slow);//重新设置数组大小

or

int fast=0,slow=0;
for(;fast<s.size();fast++){
     if(s[fast]!=' '){//1.快指针指向字母时
         if(slow!=0){//4.如果不是开头
             s[slow]=' ';//4.补上空格
             slow++;
         }
         while(fast<s.size()&&s[fast]!=' '){
             s[slow]=s[fast];//2.将单词复制过来
             slow++;fast++;
         }
     }
     //3.然后跳过了两个单词的所有空格,快指针直接指向下一个单词的首字母
 }

2&3:

reverse(s.begin(),s.end());
int i=0;
 for(int j=0;j<=s.size();j++){
     if(s[j]==' ' || j==s.size()){
         reverse(s.begin()+i,s.begin()+j);
         i=j+1;//设置开头
         j++;
     }
 }
       

右旋字符串

右旋字符串

思路

一开始我想的是直接resize扩容,用多余的空间记录后面k个单词,然后用双指针向前填充。
但这样比较麻烦,而且要申请新的空间。
后来看了要求发现只能在本串上操作:
由于要使后面k个到最前面,所以可以先整体翻转,再分别局部翻转。reverse要用到库函数algorithm

#include<iostream>
#include<algorithm>
using namespace std;
int main(){
    int k;
    string s;
    cin>>k>>s;
    reverse(s.begin(),s.end());
    reverse(s.begin(),s.begin()+k);
    reverse(s.begin()+k,s.end());
    cout<<s;
    
}

28. 实现 strStr()

28.实现strStr()
KMP算法:
常应用在字符串的查找上。
传统暴力算法遇到不满足的比如在ababad中查找abad,当遇到第四个字母与查找字母d不等时,再从第二个字母开始一一对照。
而KMP算法分析前后缀,因为如果在查找模式串第n个字母时发现不对应,则至少前面都是一一对应的,如果有前缀和后缀相同。
在这里插入图片描述
前缀aa 和后缀aa相同,则省去了模式串前缀he文本串b前面aa对比的必要,直接让模式串的j指向前缀的下一个字母b,跳过之前已经匹配过的地方。

计算前缀表

void getnext(int *next,string &s){
   int j=0;//prefix,前缀末尾
    next[0]=0;//a无相等前缀后缀
    for(int i=1;i<s.size();i++){
        while(j>0&&s[j]!=s[i]){//当前前缀和后缀的末尾不同,但前面都相同
            //所以再往前找最长相同前后缀ffaf(d)ffaf(f)
            //d与f不同,
            j=next[j-1];
        }
        if(s[j]==s[i]){
            j++;
        }
        next[i]=j;
        
    }
}

在这里插入图片描述

int strStr(string haystack, string neddle) {
    vector<int> next(neddle.size());//创建前缀表
    getprefixtable(&next[0],neddle);//计算前缀表
    for(int j=0,i=0;i<haystack.size();i++){
        while(j>0&&haystack[i]!=neddle[j]){
            j=next[j-1];
        }
        if(haystack[i]==neddle[j]){
            j++;
        }
        if(j==neddle.size())
            return i-neddle.size()+1;
    }
    return -1;
}

459.重复的子字符串

枚举

子串的length只可能在[1,n/2]之间,而且必须被整除,子串的特点是j=j-length;、

bool repeatedSubstringPattern(string s) {
for(int length=1;length*2<=s.size();length++){
     if(s.size()%length==0){
         bool match=true;
         int j=length;
         for(;j<s.size();j++){
             if(s[j]!=s[j-length]){
                 match =false;
                 break;
             }
         }
         if(match){
             return true;
         }
     }
 }
 return false;
        

KMP算法

找到最长相等前后缀,如果一个字符串有子串,则它的最长相等前后缀不包含的地方则是最小子串。
在这里插入图片描述
如果剩余部分刚好能被整除,则可以依次递推使之构成整个字符串,所以为最小子串。

 //找到最长相等前后缀,若剩余部分的长度可以被整除,则为最小重复子串
vector<int> next(s.size());
next[0]=0;
for(int j=0,i=1;i<s.size();){
     if(j>0&&s[j]!=s[i]){
         j=next[j-1];
     }
     if(s[j]==s[i]){
         j++;
         next[i]=j;
         i++;
     }
     if(j==0&&s[j]!=s[i]){
         next[i]=j;
         i++;
     }
}
if(s.size()%(s.size()-next[s.size()-1])==0&&next[s.size()-1]!=0)
     return true;
 else 
     return false;
}
  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值