代码随想录 第九天 | 烤馍片(kmp)算法 ●28. 实现 strStr() ●459.重复的子字符串
烤馍片算法(kmp):为了不让遍历的指针回退,每次不相等的时候找不相等之前的字符串的最长相等前后缀。i表示目标字符串,j表示需要在目标找到的字符串的指针。最长相等前后缀的长度就是之前有多少个与needle字符串相同,直接将j跳到上一元素位置记录的最长相等前后缀长度(next数组),这样i就可以一直++,当j==needle的长度时,证明找到完整needle字符串。
leetcode:28. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode)
class Solution { public void getNext(String haystack,int[] next){ next[0] = 0; for(int i = 0,j = 0; i < haystack.length();i++){ //不相等下标就找hastack上一个。 while(j > 0 &&haystack.charAt(i) != haystack.charAt(j)){ j = next[j - 1]; } //相等++ if(haystack.charAt(i) == haystack.charAt(j) ){ j++; } //j的值就是最长相等后缀的长度 next[i] = j; } } public int strStr(String haystack, String needle) { if(needle.length() == 0){ return 0; } int [] next = new int[needle.length()]; getNext(needle,next); int j = 0; for(int i = 0;i < haystack.length();i++){ //判断字符串相等 //不相等就退needle字符串上一位置,这个位置具体的数据需要next数组 while (j > 0 && haystack.charAt(i) != needle.charAt(j)){ j = next[j-1]; } if(haystack.charAt(i) == needle.charAt(j)){ j++; } if( j == needle.length()){ //加一是因为数组起始为0 return (i - needle.length() + 1); } } return -1; } }
LeetCode:459. 重复的子字符串 - 力扣(LeetCode)(跳)
思路:最长相等前后缀不包含的子串就是最小重复子串,总长度-最长前后缀长度,剩下的只要能被总长度整除就说明是重复字符串
class Solution { public boolean repeatedSubstringPattern(String s) { if (s.equals("")) return false; int len = s.length(); // 原串加个空格(哨兵),使下标从1开始,这样j从0开始,也不用初始化了 s = " " + s; char[] chars = s.toCharArray(); int[] next = new int[len + 1]; 这里还是看上题的next吧 // 构造 next 数组过程,j从0开始(空格),i从2开始 for (int i = 2, j = 0; i <= len; i++) { // 匹配不成功,j回到前一位置 next 数组所对应的值 while (j > 0 && chars[i] != chars[j + 1]) j = next[j]; // 匹配成功,j往后移 if (chars[i] == chars[j + 1]) j++; // 更新 next 数组的值 next[i] = j; } // 最后判断是否是重复的子字符串,这里 next[len] 即代表next数组末尾的值 if (next[len] > 0 && len % (len - next[len]) == 0) { return true; } return false; } }