From bb316cd55c040fcceea47ef912a735beb295238a Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Mon, 12 Sep 2022 14:37:24 +0800 Subject: [PATCH] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../string/RepeatedSubstringPattern.java | 63 +++++++ .../com/markilue/leecode/string/StrStr.java | 167 ++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/string/RepeatedSubstringPattern.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/string/StrStr.java diff --git a/Leecode/src/main/java/com/markilue/leecode/string/RepeatedSubstringPattern.java b/Leecode/src/main/java/com/markilue/leecode/string/RepeatedSubstringPattern.java new file mode 100644 index 0000000..f5cc458 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/string/RepeatedSubstringPattern.java @@ -0,0 +1,63 @@ +package com.markilue.leecode.string; + +import org.junit.Test; + +import java.util.Arrays; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.string + * @Author: dingjiawen + * @CreateTime: 2022-09-12 12:15 + * @Description: TODO 力扣459题:重复的子字符串: + * 给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。 + * @Version: 1.0 + */ +public class RepeatedSubstringPattern { + + @Test + public void test() { + String s = "abcabcabc"; + System.out.println(repeatedSubstringPattern(s)); +// int[] next1 = getNext1(s); +// System.out.println(Arrays.toString(next1)); + } + + + /** + * 这一题也可以用经典的KMP算法进行解决,又KMP算法可知:如果string由重复子字符串组成,其next数组一定是前面全是-1,后面全是升序排列 + * 如"abcabcabc",其next数组为[-1, -1, -1, 0, 1, 2, 3, 4, 5],所以规律是最后一个数+1可以整除是-1的数 + * 速度击败74.63%,内存击败10.85% + * @param s + * @return + */ + public boolean repeatedSubstringPattern(String s) { + + int[] next1 = getNext1(s); + + int length = next1.length; + if (next1[length - 1] != -1 && length % (length - next1[length - 1] - 1) == 0) { + return true; + } + + return false; + } + + public int[] getNext1(String needle) { + int[] next = new int[needle.length()]; + next[0] = -1; + int k = -1; + for (int i = 1; i < needle.length(); ++i) { + while (k != -1 && needle.charAt(k + 1) != needle.charAt(i)) { + k = next[k]; + } + if (needle.charAt(k + 1) == needle.charAt(i)) { + ++k; + } + next[i] = k; + } + return next; + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/string/StrStr.java b/Leecode/src/main/java/com/markilue/leecode/string/StrStr.java new file mode 100644 index 0000000..c880ea3 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/string/StrStr.java @@ -0,0 +1,167 @@ +package com.markilue.leecode.string; + +import org.junit.Test; + +import java.util.Arrays; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.string + * @Author: dingjiawen + * @CreateTime: 2022-09-12 09:01 + * @Description: TODO 力扣28题:实现strStr() + * 实现strStr()函数。 + * 给你两个字符串haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。 + *

+ * 说明: + * 当needle是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。 + * 对于本题而言,当needle是空字符串时我们应当返回 0 。这与 C 语言的strstr()以及 Java 的indexOf()定义相符。 + * @Version: 1.0 + */ +public class StrStr { + + @Test + public void test() { + + String haystack = "hello"; + String needle = "ll"; + int i = strStr(haystack, needle); + System.out.println(i); + + } + + @Test + public void test1() { + + String haystack = "aaaaa"; + String needle = "bba"; + int i = strStr(haystack, needle); + System.out.println(i); + + } + + @Test + public void test2() { + + String haystack = "baabbbbababbbabab"; + String needle = "abbab"; + int i = strStr(haystack, needle); + System.out.println(i); + + } + + @Test + public void test3() { + + String haystack = "ababaabbbbababbaabaaabaabbaaaabbabaabbbbbbabbaabbabbbabbbbbaaabaababbbaabbbabbbaabbbbaaabbababbabbbabaaabbaabbabababbbaaaaaaababbabaababaabbbbaaabbbabb"; + String needle = "abbabbbabaa"; + int i = strStr(haystack, needle); + System.out.println(i); + + } + + @Test + public void test4() { + + String haystack = "ababac"; +// String needle = "abbabbbabaa"; + int[] next = getNext1(haystack); + System.out.println(Arrays.toString(next)); + + } + + + /** + * 尝试使用KMP算法:维护一个next数组,存储needle的最小前缀和最小后缀匹配的长度,从而减少从头开始匹配的次数,从而将时间复杂度从O(n*m)降到O(n+m) + * 具体内容参考代码随想录和数据结构与算法之美的讲解内容 + * 速度击败39.11%,内存击败91.79% + * + * @param haystack + * @param needle + * @return + */ + public int strStr(String haystack, String needle) { + int[] next = getNext(needle); + int j = 0; + for (int i = 0; i < haystack.length(); ++i) { + + while (j > 0 && haystack.charAt(i) != needle.charAt(j)) { + j = next[j - 1] + 1; + } + + if (haystack.charAt(i) == needle.charAt(j)) { + ++j; + } + + if (j == needle.length()) { + return i - j + 1; + } + + + } + return -1; + + } + + + public int[] getNext(String needle) { + + int[] result = new int[needle.length()]; + + for (int i = 0; i < needle.length(); i++) { + result[i] = -1; + if (i == 0) { + continue; + } + int right = i; + for (int left = i - 1; left >= 0; left--) { + boolean flag = false; + if (needle.charAt(left) == needle.charAt(right)) { + flag = true; + for (int z = left - 1, k = right - 1; z >= 0; z--, k--) { + if (needle.charAt(z) != needle.charAt(k)) { + flag = false; + break; + } + } + } + if (flag) { + result[i] = left; + break; + } + } + } + return result; + } + + /** + * 官方获取next数组的方法:精髓在于这次的next[i]可以通过上一次的next[i-1]来获取,分为两种情况: + * 1)如果next[i-1]的下一个数和next[i]的下一个数相等,那么最大子串一定是在上一个的基础上+1,对应下面的if的内容 + * 2)如果next[i-1]的下一个数和next[i]的下一个数不相等,那么寻找上一个最大子串,看看上一次最大子串的下一个数和next[i]的下一个数相等,如果不相等就寻找在上一次的,对应于下面的while内容 + * 下所述的看就是用来记录上一次最大子串的索引 + * + * 速度击败39.11%,内存击败73.88% + * 但是只用了1ms + * @param needle + * @return + */ + public int[] getNext1(String needle) { + int[] next = new int[needle.length()]; + next[0] = -1; + int k = -1; + for (int i = 1; i < needle.length(); ++i) { + while (k != -1 && needle.charAt(k + 1) != needle.charAt(i)) { + k = next[k]; + } + if (needle.charAt(k + 1) == needle.charAt(i)) { + ++k; + } + next[i] = k; + } + + return next; + + } + + +}