leetcode 796. 旋转字符串(KMP算法-java)

265 篇文章 2 订阅
235 篇文章 0 订阅
文章讨论了LeetCode第796题——旋转字符串的问题,解释了解决方案,包括使用Java的原生方法检查目标字符串是否可以通过旋转得到,以及介绍和实现了KMP算法,这是一种高效的字符串匹配算法,用于避免无效匹配,提高匹配效率。
摘要由CSDN通过智能技术生成

leetcode 796. 旋转字符串

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

题目描述

给定两个字符串, s 和 goal。如果在若干次旋转操作之后,s 能变成 goal ,那么返回 true 。
s 的 旋转操作 就是将 s 最左边的字符移动到最右边。
例如, 若 s = ‘abcde’,在旋转一次之后结果就是’bcdea’ 。

示例 1:
输入: s = “abcde”, goal = “cdeab”
输出: true

示例 2:
输入: s = “abcde”, goal = “abced”
输出: false

提示:
1 <= s.length, goal.length <= 100
s 和 goal 由小写英文字母组成

解法一 java 原生方法

由于每次旋转操作都是将最左侧字符移动到最右侧,因此如果 goal 可由 s 经过多步旋转而来,那么 goal 必然会出现在 s + s 中,即满足 (s + s).contains(goal),同时为了 s 本身过长导致的结果成立,我们需要先确保两字符串长度相等。

代码演示

  public boolean rotateString1(String s, String goal) {
        if(s.length() != goal.length()){
            return false;
        }
        String str = s + s;
        return str.indexOf(goal) == -1 ? false : true; 
    }

KMP 算法

我们主要想通过这道题,来学习下KMP算法,KMP算法的时间复杂度 和indexOf 是 一致的,

什么是KMP算法:
KMP算法(Knuth-Morris-Pratt算法)是一种用于查找字符串中是否存在某个模式的算法,时间复杂度为O(m+n),其中m是模式串的长度,n是文本串的长度。该算法是由Knuth、Morris和Pratt三人于1977年共同提出的,它利用了模式串的前缀信息来避免无效的匹配,从而提高匹配效率。

KMP算法的核心思想是,当模式串中的某个字符与文本串中的某个字符不匹配时,能够利用模式串的前缀信息快速跳过一定的文本串长度,避免从下一个字符重新开始匹配。具体来说,KMP算法通过构建一个跳转表(也称为失配表或next数组),来记录模式串中每个位置之前的最长公共前后缀长度。

构建跳转表的过程如下:

  1. 初始化一个长度为m的next数组,其中next[0]=-1,表示模式串的第一个字符之前没有前缀可以跳转。
  2. 从模式串的第二个字符开始,遍历模式串和next数组:

a. 当模式串的当前字符与文本串的当前字符匹配时,继续向前匹配。
b. 当模式串的当前字符与文本串的当前字符不匹配时,需要找到一个位置进行跳转。这个位置就是next[i-1],即模式串中前一个不匹配的位置。由于next数组记录的是最长公共前后缀长度,因此可以从next[i-1]处跳转到next[i],而不用重新从文本串的下一个字符开始匹配。
c. 在跳转的过程中,需要更新next数组:如果模式串的下一个字符与文本串的当前字符匹配,则将next[i+1]=next[i]+1;否则,从模式串的下一个字符重新开始遍历,即next[i]=0。

  1. 跳转表构建完成后,就可以利用它来进行匹配操作了。从文本串的第一个字符开始,按照上述方法进行匹配,直到找到一个位置i,满足模式串中从0到i的子串与文本串中从0到i的子串完全匹配,或者无法继续匹配为止。

KMP算法是一种经典的字符串匹配算法,它利用了模式串的前缀信息,避免了无效的匹配,提高了匹配效率。在实际应用中,KMP算法被广泛应用于字符串处理、文本处理、模式识别等领域。

具体算法代码 可以查看KMP–高效字符串匹配算法

代码演示

 /**
     * 旋转字符串
     * @param a
     * @param b
     * @return
     */
    public static boolean rotateString(String a, String b) {
        if (a == null || b == null || a.length() != b.length()) {
            return false;
        }
        String b2 = b + b;
        return getIndexOf(b2, a) != -1;
    }
    /**
     * KMP 查找子串出现的第一个位置,没有返回-1.
     * 类似java的 indexOf();
     * @param s
     * @param m
     * @return
     */
    public static int getIndexOf(String s, String m) {
        if (s.length() < m.length()){
            return -1;
        }
        char[] ss = s.toCharArray();
        char[] ms = m.toCharArray();
        int si = 0;
        int mi = 0;
        int[] next = getNextArray(ms);
        while (si < ss.length && mi < ms.length){
            if (ss[si] == ms[mi]){
                si++;
                mi++;
            } else if (next[mi] == -1) {
                si++;
            }else{
                mi = next[mi];
            }
        }
        return mi == ms.length ? si - mi : -1;
    }


    public static int[] getNextArray(char[] ms) {
        if (ms.length == 1){
            return new int[]{-1};
        }
        int[] next = new int[ms.length];
        next[0] = -1;
        next[1] = 0;
        int pos = 2;
        int cn = 0;
        while (pos < ms.length){
            if (ms[pos - 1] == ms[cn]){
                next[pos++] = ++cn;
            } else if (cn > 0) {
                cn = next[cn];
            }else{
                next[pos++] = 0;
            }
        }

        return next;
    }

KMP算法

KMP–高效字符串匹配算法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值