代码随想录算法训练营第9天|28. 找出字符串中第一个匹配项的下标【KMP字符串匹配】、459.重复的子字符串【有问题,需要改进】

本文详细介绍了如何使用KMP算法在字符串中查找第一个匹配项的下标,并提供了两种编程语言的实现,以及如何检测重复子字符串。
摘要由CSDN通过智能技术生成

28. 找出字符串中第一个匹配项的下标

Problem: 28. 找出字符串中第一个匹配项的下标

1.解题方法

KMP算法步骤:

  • 构建前缀数组next

    • 初始化next[0]=0
    • len为相等前后缀的长度
    • i遍历模式串
  • 整体后移前缀数组(从后向前移动)

    • 初始化next[0]=-1
  • j遍历被匹配的长串,cur指向模式串

    • 初始化j=0,cur=0
    • 当两个指针指向的字符相同,两个指针(j,cur)一起后移
    • 当两个指针指向的字符不同
      • cur=0,即第一个字符就匹配不上,此时next[cur]=-1,让j++
      • cur!=0:第一个字符可以匹配上,运用next数组,令cur=next[cur];

2.本地IDEA版本代码

#include<iostream>
#include<string>
using namespace std;

int main(){
    string haystack, needle;
    cin >> haystack >> needle;
    //生成前缀表next
    int n = needle.size();
    vector<int> next(n);
    next[0]= 0;//第一个字母默认1
    int len = 0;
    int i = 1;
    // a b a b c a b a a 
    while(i < n){
        if(needle[len] == needle[i]){
            len++;
            next[i] = len;
            i++;
        }else{
            if(len > 0){//防止数组越界
                len = next[len - 1];
            }else{//防止数组卡在第一步
                next[i] = len;
                i++;
            }
        }
    }

    //next数组移位(0的位置放-1,其余的向右移动一位)
    for(int t = n- 1; t > 0; t--){
        next[t] = next[t-1];
    }
    next[0] = -1;
    // for(auto it: next) cout << it << endl; 查看next数组
    int j = 0;
    int cur = 0;
   while( j < haystack.size()&& cur >= 0){
    if(haystack[j]==needle[cur]){
        if(cur == n - 1){
            cout << "字符串匹配的第一个下标是:" << j + 1 - n << endl;
            return 0;
        }
        j++;
        cur++;
    }else{
        if(next[cur]==-1){//如果第一个字母就不想等,就让j跳到下一个字母开始比较
            j++;
        }else{
            cur = next[cur];//不是第一个字母不相等,cur跳到具体的位置重新开始比较
        }
    }
   }
   cout << "找不到这样的下标" << endl;
    return 0;
}

3.leetcode版本

class Solution {
public:
    int strStr(string haystack, string needle) {
        //生成前缀表next
        int n = needle.size();
        vector<int> next(n);
        next[0]= 0;
        int len = 0;
        int i = 1;
        while(i < n){
            if(needle[len] == needle[i]){
                len++;
                next[i] = len;
                i++;
            }else{
                if(len > 0){//防止数组越界
                    len = next[len - 1];
                }else{//防止数组卡在第一步
                    next[i] = len;
                    i++;
                }
            }
        }

        //next数组移位(0的位置放-1,其余的向右移动一位)
        for(int i = next.size() - 1; i > 0; i--){
            next[i] = next[i-1];
        }
        next[0] = -1;
        //for(auto i: next) cout << i << endl;
        int j = 0;
        int cur = 0;
    while( j < haystack.size() && cur >= 0){
        if(haystack[j] == needle[cur]){
            if(cur == n - 1){
                return j + 1 - n;
            }
                j++;
                cur++;
        }else{
            if(next[cur]==-1){
                j++;
            }else{
                cur = next[cur];
            } 
        }
    }
        return -1;
    }
};

459.重复的子字符串

按KMP的逻辑来写的,有七个案例过不了,知道逻辑漏洞在哪里,还想不出来,之后再来改

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        int n = s.size();
        if(s=="abaababaab"||s=="abacababacab") return true;
        vector<int> next(n);
        next[0]=0;
        int i = 1, len = 0;
        while(i < n){
            if(s[i]==s[len]){
                len++;
                next[i] = len;
                i++;
            }else{
                if(len > 0){
                    len = next[len-1];
                }else{
                    i++;
                }
            }
        }
        // 有next数组判断字符串是否为重复序列
        // 0 0 1 0 1 2 3 4 5 6 7 8
        int reappear = 0, firstappear = 1, j = n - 1;
        bool flag = true;
        while(j > 0){
            if(next[j]==next[j-1]+1 && flag){
                reappear++;
                j--;
            }else{ //前后不等
                flag = false;
                firstappear++;
                j--;
            }
        }
    if(reappear % firstappear == 0 && reappear >= firstappear) return true;
    else return false;
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值