Java C++题解leetcode字符串轮转KMP算法详解

目录
  • 题目要求
  • 思路一:双指针(模拟)
    • Java
    • C++
  • 思路二:子串
    • 手写KMP
      • Java
      • dp
      • C++
      • dp
    • 调API
      • Java
      • C++
  • 总结

题目要求

思路一:双指针(模拟)

Java

class Solution {
    public boolean isFlipedString(String s1, String s2) {
        if (s1.length() != s2.length())
            return false;
        int n = s1.length();
        if (n == 0)
            return true;
        for (int i = 0; i < n; i++) {
            boolean res = true;
            for (int j = 0; j < n; j++) {
                if (s1.charAt((i + j) % n) != s2.charAt(j)) {
                    res = false;
                    break;
                }
            }
            if (res)
                return true;
        }
        return false;
    }
}
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1)

C++

class Solution {
public:
    bool isFlipedString(string s1, string s2) {
        if (s1.size() != s2.size())
            return false;
        int n = s1.size();
        if (n == 0)
            return true;
        for (int i = 0; i < n; i++) {
            bool res = true;
            for (int j = 0; j < n; j++) {
                if (s1[(i + j) % n] != s2[j]) {
                    res = false;
                    break;
                }
            }
            if (res)
                return true;
        }
        return false;
    }
};
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1)

思路二:子串

手写KMP

KMP的思路可以参考KMP 算法详解和详解KMP算法

Java

get_next

class Solution {
    public boolean isFlipedString(String s1, String s2) {
        if (s1.length() != s2.length())
            return false;
        int n = s1.length();
        if (n == 0)
            return true;
        int[] nxt = new int[n];
        nxt[0] = -1;
        int j = 0; // pat指针
        int k = -1; // 跳转位置
        while (j &lt; n - 1) {
            if (k == -1 || s2.charAt(j) == s2.charAt(k)) {
                if (s2.charAt(++j) == s2.charAt(++k))
                    nxt[j] = nxt[k]; // 连续相同
                else
                    nxt[j] = k;
            }
            else
                k = nxt[k];
        }
        String txt = s1 + s1;
        j = 0;
        for (int i = 0; i &lt; 2 * n; i++) {
            if (j &lt; n &amp;&amp; txt.charAt(i) == s2.charAt(j))
                j++;
            else {
                j = nxt[j];
                if (j == -1)
                    j++;
            }
            if (j == n)
                return true;
        }
        return false;
    }
}

dp

class Solution {
    public boolean isFlipedString(String s1, String s2) {
        if (s1.length() != s2.length())
            return false;
        int n = s1.length();
        if (n == 0)
            return true;
        int[][] dp = new int[n][256]; // dp[state][char] = nxt state
        dp[0][s2.charAt(0)] = 1;
        int x = 0; // 影子状态
        for (int s = 1; s < n; s++) {
            for (int c = 0; c < 256; c++)
                dp[s][c] = dp[x][c];
            dp[s][s2.charAt(s)] = s + 1;
            x = dp[x][s2.charAt(s)];
        }
        String txt = s1 + s1;
        int state = 0;
        for (int i = 0; i < 2 * n; i++) {
            state = dp[state][txt.charAt(i)];
            if (state == n)
                return true;
        }
        return false;
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

C++

get_next

class Solution {
public:
    bool isFlipedString(string s1, string s2) {
        if (s1.size() != s2.size())
            return false;
        int n = s1.size();
        if (n == 0)
            return true;
        int nxt[n];
        nxt[0] = -1;
        int j = 0; // pat指针
        int k = -1; // 跳转位置
        while (j < n - 1) {
            if (k == -1 || s2[j] == s2[k]) {
                if (s2[++j] == s2[++k])
                    nxt[j] = nxt[k]; // 连续相同
                else
                    nxt[j] = k;
            }
            else
                k = nxt[k];
        }
        string txt = s1 + s1;
        j = 0;
        for (int i = 0; i < 2 * n; i++) {
            if (j < n && txt[i] == s2[j])
                j++;
            else {
                j = nxt[j];
                if (j == -1)
                    j++;
            }
            if (j == n)
                return true;
        }
        return false;
    }
};

dp

class Solution {
public:
    bool isFlipedString(string s1, string s2) {
        if (s1.size() != s2.size())
            return false;
        int n = s1.size();
        if (n == 0)
            return true;
        int dp[n][256]; // dp[state][char] = nxt state
        memset(dp, 0, sizeof(dp));
        dp[0][s2[0]] = 1;
        int x = 0; // 影子状态
        for (int s = 1; s < n; s++) {
            for (int c = 0; c < 256; c++)
                dp[s][c] = dp[x][c];
            dp[s][s2[s]] = s + 1;
            x = dp[x][s2[s]];
        }
        string txt = s1 + s1;
        int state = 0;
        for (int i = 0; i < 2 * n; i++) {
            state = dp[state][txt[i]];
            if (state == n)
                return true;
        }
        return false;
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

调API

Java

class Solution {
    public boolean isFlipedString(String s1, String s2) {
        return s1.length() == s2.length() && (s1 + s1).contains(s2);
    }
}
  • 时间复杂度:O(n),取决于语言匹配子字符串机制
  • 空间复杂度:O(n)

C++

class Solution {
public:
    bool isFlipedString(string s1, string s2) {
        return s1.size() == s2.size() && (s1 + s1).find(s2) != string::npos;
    }
};
  • 时间复杂度:O(n),取决于语言匹配子字符串机制
  • 空间复杂度:O(n)
impl Solution {
    pub fn is_fliped_string(s1: String, s2: String) -> bool {
        s1.len() == s2.len() && s2.repeat(2).contains(&s1)
    }
}
  • 时间复杂度:O(n),取决于语言匹配子字符串机制
  • 空间复杂度:O(n)

总结

做过了轮转的题就能很快意识到拼接然后找子串,本来调个API结束结果发现了KMP算法,就浅学一下~

时间耗在算法了就掠过rust各种辣~

以上就是Java C++题解leetcode字符串轮转KMP算法详解的详细内容,更多关于Java C++ 字符串轮转KMP算法的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java C++题解leetcode消失的两个数字实例

    目录 题目要求 思路:数学推导 Java C++ Rust 总结 题目要求 思路:数学推导 不重复的数组序列可以根据高斯公式计算所有元素的总和: 用当前数组长度加上两个缺失的数字可以得到所有数字长度,即可应用公式. 减去当前数组和即可得到缺失数字和sumsumsum: 两个缺失的数字分别位于m=sum2m=\frac{sum}{2}m=2sum两边: 遍历当前数组中所有小于(或大于)mmm的值,找到缺失的一个: 同样利用两个“和”的差值得到: 利用sumsumsum即可得到另一个. Java c

  • Java C++题解leetcode判定是否为字符重排

    目录 题目要求 思路一:排序 Java C++ Rust 思路二:词频统计 Java C++ Rust 总结 题目要求 思路一:排序 Java class Solution { public boolean CheckPermutation(String s1, String s2) { if(s1.length() != s2.length()) return false; char[] sort1 = s1.toCharArray(); Arrays.sort(sort1); char[]

  • Java C++ 题解leetcode1619删除某些元素后数组均值

    目录 题目要求 思路:模拟 Java C++ Rust 题目要求 思路:模拟 根据题意模拟即可: 排序然后只取中间符合条件的数加和然后计算均值: 根据给出的数组长度n为20的倍数,5%可直接取n/20: 两边各去除5%,则剩余长度为0.9n. Java class Solution { public double trimMean(int[] arr) { Arrays.sort(arr); int n = arr.length, tot = 0; for (int i = n / 20; i

  • Java C++题解 leetcode第k个数实例

    目录 题目要求 思路一:小根堆 Java C++ 思路二:多路归并[多指针] Java C++ Rust 总结 题目要求 思路一:小根堆 中文题目描述不太清晰,但其实由题目可以发现,当x满足条件时,3x.5x.7x分别也都满足条件. 将满足条件的数依次放入优先队列存放用于后续计算,由于每次要取待计算队列中最小的数x,所以定义小根堆: 弹出x,计算3x.5x.7x并入队: 用一个哈希表记录防止重复入队. 每次取数(pop)时进行计数,到第k次结束,当前队首即为答案. Java <学到了> 1L也

  • Java C++题解leetcode1598文件夹操作日志搜集器

    目录 题目要求 思路:模拟 Java C++ Rust 总结 题目要求 思路:模拟 根据日志判断目前在哪一级子文件夹即可,级数就等于返回时的步数,主文件夹级数初始为000: xl:级数+1+1+1: ./:级数不变: ../:级数−1-1−1. Java class Solution { public int minOperations(String[] logs) { int res = 0; for (String l : logs) { if (l.equals("../"))

  • Java C++题解leetcode672灯泡开关示例

    目录 题目要求 思路:找规律 Java C++ Rust 总结 题目要求 思路:找规律 找到尽可能最精简的通项表达,今日参考:京城打工人 首先,归纳每个开关会影响的灯,其中(k=0,1,2,…): 开关 反转灯编号 一 k 二 2k 三 2k+1 四 3k+1 可见灯以6盏为周期具有相同变化,所以以下只需要推导第一个周期里的6盏灯即可. 观察前6盏灯: 灯 开关 1 一.三.四 2 一.二 3 一.三 4 一.二.四 5 一.三 6 一.二 发现灯2.6和3.5分别受同样的开关影响,所以状态相同

  • Java C++题解leetcode字符串轮转KMP算法详解

    目录 题目要求 思路一:双指针(模拟) Java C++ 思路二:子串 手写KMP Java dp C++ dp 调API Java C++ 总结 题目要求 思路一:双指针(模拟) Java class Solution { public boolean isFlipedString(String s1, String s2) { if (s1.length() != s2.length()) return false; int n = s1.length(); if (n == 0) retu

  • Java数据结构之KMP算法详解以及代码实现

    目录 暴力匹配算法(Brute-Force,BF) 概念和原理 next数组 KMP匹配 KMP全匹配 总结 我们此前学了前缀树Trie的实现原理以及Java代码的实现.Trie树很好,但是它只能基于前缀匹配实现功能.但是如果我们的需求是:一个已知字符串中查找子串,并且子串并不一定符合前缀匹配,那么此时Trie树就无能为力了. 实际上这种字符串匹配的需求,在开发中非常常见,例如判断一个字符串是否包括某些子串,然后进行分别的处理. 暴力匹配算法(Brute-Force,BF) 这是最常见的算法字符

  • Java语言实现快速幂取模算法详解

    快速幂取模算法的引入是从大数的小数取模的朴素算法的局限性所提出的,在朴素的方法中我们计算一个数比如5^1003%31是非常消耗我们的计算资源的,在整个计算过程中最麻烦的就是我们的5^1003这个过程 缺点1:在我们在之后计算指数的过程中,计算的数字不都拿得增大,非常的占用我们的计算资源(主要是时间,还有空间) 缺点2:我们计算的中间过程数字大的恐怖,我们现有的计算机是没有办法记录这么长的数据的,所以说我们必须要想一个更加高效的方法来解决这个问题 当我们计算AB%C的时候,最便捷的方法就是调用Ma

  • Java常用类之字符串相关类使用详解

    目录 字符串相关类 1.String类的使用 2.理解String类源码 3.使用StringBuilder类 4.StringBuilder类源码 字符串相关类 String.StringBuilder.StringBuffer类是三个字符串相关类. String类代表不可变字符序列,StringBuilder类和StringBuffer类代表可变字符序列. 关于这三个类的详细的用法,在笔试和面试以及实际开发中经常能用到,我们必须掌握好它. 1.String类的使用 String的常用方法:

  • Java数据结构之图的路径查找算法详解

    目录 前言 算法详解 实现 API设计 代码实现 前言 在实际生活中,地图是我们经常使用的一种工具,通常我们会用它进行导航,输入一个出发城市,输入一个目的地 城市,就可以把路线规划好,而在规划好的这个路线上,会路过很多中间的城市.这类问题翻译成专业问题就是: 从s顶点到v顶点是否存在一条路径?如果存在,请找出这条路径. 例如在上图上查找顶点0到顶点4的路径用红色标识出来,那么我们可以把该路径表示为 0-2-3-4. 如果对图的前置知识不了解,请查看系列文章: [数据结构与算法]图的基础概念和数据

  • Java垃圾回收之分代收集算法详解

    概述 这种算法,根据对象的存活周期的不同将内存划分成几块,新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法.可以用抓重点的思路来理解这个算法. 新生代对象朝生夕死,对象数量多,只要重点扫描这个区域,那么就可以大大提高垃圾收集的效率.另外老年代对象存储久,无需经常扫描老年代,避免扫描导致的开销. 新生代 在新生代,每次垃圾收集器都发现有大批对象死去,只有少量存活,采用复制算法,只需要付出少量存活对象的复制成本就可以完成收集:可以参看我之前写的Java垃圾回收之复制算法详解 老年代

  • java 中冒泡、二分、快速算法详解

    1.冒泡算法的原理: 冒泡排序算法的一般性策略:搜索整个值列,比较相邻元素,如果两者的相对次序不对,则交换它们,其结果是最大值"想水泡一样"移动到值列的最后一个位置上,这也是它在最终完成排序的值列中合适的位置.然后再次搜索值列,将第二大的值移动至倒数第二个位置上,重复该过程,直至将所有元素移动到正确的位置上. 下面是两个Java冒泡算法程序 2.冒泡代码如下: public class BubbleSort { public static void bubbleSort(int[] a

  • Java字符拼接成字符串的注意点详解

    这两天敲代码的时候,偶然间发现一个好玩的事情,分享一下,记录一下. 该段代码主要是:先产生的几个整数,把整数转换成对应的字符,最后的字符拼接成字符串,在把字符拼接成字符串的时候,个人因为偷懒使用+号进行操作,出现了一点小惊喜.拼接以后出现了两种不同的结果,感到十分的意外,所以分析了一下出现的结果,记录一下. package top.supertd.www; import java.util.concurrent.ThreadLocalRandom; public class TestString

  • Java C++题解leetcode 1684统计一致字符串的数目示例

    目录 题目 思路:模拟 Java C++ Rust 题目 题目要求 思路:模拟 用一个哈希表记录可出现的字母,然后逐一遍历每个单词每个字母,符合条件则结果加一. Java class Solution { public int countConsistentStrings(String allowed, String[] words) { boolean[] hash = new boolean[26]; for (var a : allowed.toCharArray()) hash[a -

随机推荐