【Day4】字符串与字符串匹配 KMP算法

03.02.07 练习题目(第 04 天)

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

1.1 题目大意

描述:给定两个字符串 haystackneedle

要求:在 haystack 字符串中找出 needle 字符串出现的第一个位置(从 0 开始)。如果不存在,则返回 -1

说明

  • needle 为空字符串时,返回 0
  • 1 ≤ h a y s t a c k . l e n g t h , n e e d l e . l e n g t h ≤ 1 0 4 1 \le haystack.length, needle.length \le 10^4 1haystack.length,needle.length104
  • haystackneedle 仅由小写英文字符组成。

示例

输入:haystack = "hello", needle = "ll"
输出:2
解释:"sad" 在下标 06 处匹配。第一个匹配项的下标是 0 ,所以返回 0 。

输入:haystack = "leetcode", needle = "leeto"
输出:-1
解释:"leeto" 没有在 "leetcode" 中出现,所以返回 -1

我的答案

//原始
class Solution {
public:
    int strStr(string haystack, string needle) {
        int m = haystack.size(),n = needle.size();
        if(n > m) return -1;
        int ans = INT_MAX;
        for(int j = 0;j<m;++j){
            if( haystack[j] == needle[0]){
                bool issame = false;
                for(int i = 0; i < n;++i){
                    if(haystack[j+i] == needle[i]) issame = true;
                    else {
                        issame = false;
                        break;
                        }
                }
                if(issame) return j;
                // ans = ;
            }
        }
        return -1;
    }
};
//优化后:
class Solution {
public:
    int strStr(string haystack, string needle) {
        int m = haystack.size(), n = needle.size();
        if (n == 0) return 0; // 如果 needle 为空,返回 0
        if (n > m) return -1; // 如果 needle 比 haystack 长,返回 -1

        for (int j = 0; j <= m - n; ++j) { // 只需要遍历到 haystack 中剩余的字符数大于等于 needle 的长度
            if (haystack[j] == needle[0]) {
                int i = 0;
                while (i < n && haystack[j + i] == needle[i]) {
                    ++i;
                }
                if (i == n) return j; // 如果找到完全匹配的子串,返回起始位置
            }
        }
        return -1; // 如果没有找到匹配的子串,返回 -1
    }
};

其他答案

//KMP方法
class Solution {
public:
    int strStr(string haystack, string needle) {
        if (needle.empty()) return 0; // 如果needle为空,返回0

        // 构建next数组
        vector<int> next(needle.length());
        int j = 0;
        next[0] = 0; // next数组的第一个值总是0
        for (int i = 1; i < needle.length(); ++i) {
            while (j > 0 && needle[i] != needle[j]) {
                j = next[j - 1]; // 如果不匹配,就向前移动j
            }
            if (needle[i] == needle[j]) {
                j++; // 如果匹配,就增加j
            }
            next[i] = j; // 将j的值赋给next[i]
        }

        // 使用next数组进行KMP搜索
        j = 0;
        for (int i = 0; i < haystack.length(); ++i) {
            while (j > 0 && haystack[i] != needle[j]) {
                j = next[j - 1]; // 如果不匹配,就根据next数组移动模式串
            }
            if (haystack[i] == needle[j]) {
                j++; // 如果匹配,就增加j
            }
            if (j == needle.length()) {
                return i - j + 1; // 找到匹配,返回起始索引
            }
        }
        return -1; // 没有找到匹配
    }
};

心得

  1. KMP算法

    知乎: KMP算法介绍
    b站: 懒猫老师-数据结构-(15)KMP算法2-next数组(模式匹配,字符串匹配)

2. 0459. 重复的子字符串

2.1 题目大意

描述:给定一个非空的字符串 s

要求:检查该字符串 s 是否可以通过由它的一个子串重复多次构成。

说明

  • 1 ≤ s . l e n g t h ≤ 1 0 4 1 \le s.length \le 10^4 1s.length104
  • s 由小写英文字母组成

示例

输入: s = "abab"
输出: true
解释: 可由子串 "ab" 重复两次构成。


输入: s = "aba"
输出: false

我的答案

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        string doubled = s + s;
        string withoutFirstAndLast = doubled.substr(1, doubled.size() - 2);
        return withoutFirstAndLast.find(s) != string::npos;
    }
};

3. 0686. 重复叠加字符串匹配

3.1 题目大意

描述:给定两个字符串 ab

要求:寻找重复叠加字符串 a 的最小次数,使得字符串 b 成为叠加后的字符串 a 的子串,如果不存在则返回 -1

说明

  • 字符串 "abc" 重复叠加 0 次是 "",重复叠加 1 次是 "abc",重复叠加 2 次是 "abcabc"
  • 1 ≤ a . l e n g t h ≤ 1 0 4 1 \le a.length \le 10^4 1a.length104
  • 1 ≤ b . l e n g t h ≤ 1 0 4 1 \le b.length \le 10^4 1b.length104
  • ab 由小写英文字母组成。

示例

输入:a = "abcd", b = "cdabcdab"
输出:3
解释:a 重复叠加三遍后为 "abcdabcdabcd", 此时 b 是其子串。


输入:a = "a", b = "aa"
输出:2

我的答案

#include <string>
using namespace std;

class Solution {
public:
    int repeatedStringMatch(string a, string b) {
        // 计算最少需要重复的次数
        int times = (b.length() + a.length() - 1) / a.length(); // 向上取整
        
        // 构造重复 times 次的字符串
        string repeated_a = "";
        for (int i = 0; i < times; ++i) {
            repeated_a += a;
        }
        
        // 检查 b 是否是 repeat_a 的子串
        if (repeated_a.find(b) != string::npos) {
            return times;
        }
        
        // 如果 b 不是 repeat_a 的子串,再尝试多重复一次
        repeated_a += a;
        if (repeated_a.find(b) != string::npos) {
            return times + 1;
        }
        
        // 如果仍然不是子串,返回 -1
        return -1;
    }
};
  • 23
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值