leetcode 686. 重复叠加字符串匹配(KMP算法-java)

265 篇文章 2 订阅
235 篇文章 0 订阅

leetcode 686. 重复叠加字符串匹配

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/repeated-string-match

题目描述

给定两个字符串 a 和 b,寻找重复叠加字符串 a 的最小次数,使得字符串 b 成为叠加后的字符串 a 的子串,如果不存在则返回 -1。
注意:字符串 “abc” 重复叠加 0 次是 “”,重复叠加 1 次是 “abc”,重复叠加 2 次是 “abcabc”。

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

示例 2:
输入:a = “a”, b = “aa”
输出:2

示例 3:
输入:a = “a”, b = “a”
输出:1

示例 4:
输入:a = “abc”, b = “wxyz”
输出:-1

提示:
1 <= a.length <= 10000
1 <= b.length <= 10000
a 和 b 由小写英文字母组成

KMP 算法

首先想明白一个问题,如果叠加后含有b,那么起始位置,一定是在a的某一个位置.
在这里插入图片描述

因此我们可以先复制出长度大于b字符串长度的字符串,然后根据kmp算法,看b是否是a叠加后的字串,就可以得出,得出需要复制的次数(在叠加时,记录叠加的次数).

代码演示

  /**
     * leetcode 686. 重复叠加字符串匹配
     * @param a
     * @param b
     * @return
     */
    public int repeatedStringMatch(String a, String b) {
        StringBuilder sb = new StringBuilder();
        int time = 0;
        //当长度大于b 的长度时,就退出
        while (sb.length() < b.length()){
            time++;
            sb.append(a);
        }
        sb.append(a);
        int indexOf = getIndexOf(sb.toString(), b);
        if (indexOf == -1){
            return -1;
        }
        return indexOf + b.length() > a.length() * time ? time + 1 : time;
    }

    /**
     * 判断s2 是否是 s1的子串. 返回出现的第一个字母的下标
     * @param s1
     * @param s2
     * @return
     */
    public  int getIndexOf(String s1, String s2) {
        if (s1 == null || s2 == null || s1.length() == 0 || s1.length() < s2.length()){
            return -1;
        }
        char[] str1 = s1.toCharArray();
        char[] str2 = s2.toCharArray();
        int[] next = getNextArray(str2);
        int x = 0;
        int y = 0;
        while (x < str1.length && y < str2.length){
            if (str1[x] == str2[y]){
                //相等时 去下一个位置去比较
                x++;
                y++;
            } else if (next[y] == -1) {
                x++;
            }else {
                y = next[y];
            }
        }
        return y == str2.length ? x - y : -1;
    }

    /**
     * 前缀和后缀相等的长度数组
     * @param str
     * @return
     */
    public int[] getNextArray(char[] str){
        if(str.length == 1){
            return new int[]{-1};
        }
        int n = str.length;
        int[] next = new int[n];
        next[0] = -1;
        next[1] = 0;
        int i = 2;
        int hc = 0;
        while (i < n){
            if (str[i - 1] == str[hc]){
                next[i++] = ++hc;
            } else if (hc > 0) {
                hc = next[hc];
            }else {
                next[i++] = 0;
            }
        }
        return next;
    }

KMP 算法

KMP–高效字符串匹配算法

KMP算法是一种字符串匹配算法,用于在一个文本串S内查找一个模式串P的出现位置。它的时间复杂度为O(n+m),其中n为文本串的长度,m为模式串的长度。 KMP算法的核心思想是利用已知信息来避免不必要的字符比较。具体来说,它维护一个next数组,其中next[i]表示当第i个字符匹配失败时,下一次匹配应该从模式串的第next[i]个字符开始。 我们可以通过一个简单的例子来理解KMP算法的思想。假设文本串为S="ababababca",模式串为P="abababca",我们想要在S中查找P的出现位置。 首先,我们可以将P的每个前缀和后缀进行比较,得到next数组: | i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | | --- | - | - | - | - | - | - | - | - | | P | a | b | a | b | a | b | c | a | | next| 0 | 0 | 1 | 2 | 3 | 4 | 0 | 1 | 接下来,我们从S的第一个字符开始匹配P。当S的第七个字符和P的第七个字符匹配失败时,我们可以利用next[6]=4,将P向右移动4个字符,使得P的第五个字符与S的第七个字符对齐。此时,我们可以发现P的前五个字符和S的前五个字符已经匹配成功了。因此,我们可以继续从S的第六个字符开始匹配P。 当S的第十个字符和P的第八个字符匹配失败时,我们可以利用next[7]=1,将P向右移动一个字符,使得P的第一个字符和S的第十个字符对齐。此时,我们可以发现P的前一个字符和S的第十个字符已经匹配成功了。因此,我们可以继续从S的第十一个字符开始匹配P。 最终,我们可以发现P出现在S的第二个位置。 下面是KMP算法的C++代码实现:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值