JAVA代码编写
给你两个字符串 haystack
和 needle
,请你在 haystack
字符串中找出 needle
字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle
不是 haystack
的一部分,则返回 -1
。
示例 1:
输入:haystack = "sadbutsad", needle = "sad"
输出:0
解释:"sad" 在下标 0 和 6 处匹配。
第一个匹配项的下标是 0 ,所以返回 0 。
示例 2:
输入:haystack = "leetcode", needle = "leeto"
输出:-1
解释:"leeto" 没有在 "leetcode" 中出现,所以返回 -1 。
提示:
1 <= haystack.length, needle.length <= 104
haystack
和 needle
仅由小写英文字符组成
教程:https://programmercarl.com/0028.%E5%AE%9E%E7%8E%B0strStr.html
思路:如果needle字符串长度大于haystack的,返回-1.
两个for循环,默认初始flag为true,i为匹配字符串的起始位置,j为匹配字符串的终止位置,遍历的时候比较每个字符串是否相等,有不等的就设置flag为false,停止循环,更新i,再进行变量。
复杂度分析:
时间复杂度: O ( ( n − m + 1 ) ∗ m ) O((n-m+1)*m) O((n−m+1)∗m)
空间复杂度: O ( 1 ) O(1) O(1)
class Solution {
public int strStr(String haystack, String needle) {
int n = haystack.length();
int m = needle.length();
if (m > n) return -1;
for (int i = 0; i <= n - m; i++) {
boolean flag = true;
for (int j = 0; j < m; j++) {
if (haystack.charAt(i + j) != needle.charAt(j)) {
flag = false;
break;
}
}
if (flag) return i;
}
return -1;
}
}
原谅我知道用两层for循环,但是代码细节部分还是会出错,有时整debug还老半天
思路:这个和for循环有点像,这里的i是在haystack中找到第一个和needle一样的字符,然后再比较i之后的字符串和needle是否相同。
复杂度分析:
时间复杂度: O ( m ∗ n ) O(m*n) O(m∗n),n为haystack的长度,m为needle的长度
空间复杂度: O ( 1 ) O(1) O(1)
class Solution {
public int strStr(String haystack, String needle) {
int m = needle.length();
// 当 needle 是空字符串时我们应当返回 0
if (m == 0) {
return 0;
}
int n = haystack.length();
if (n < m) {
return -1;
}
int i = 0;
int j = 0;
while (i < n - m + 1) {
// 找到首字母相等
while (i < n && haystack.charAt(i) != needle.charAt(j)) {
i++;
}
if (i == n) {// 没有首字母相等的
return -1;
}
// 遍历后续字符,判断是否相等
i++;
j++;
while (i < n && j < m && haystack.charAt(i) == needle.charAt(j)) {
i++;
j++;
}
if (j == m) {// 找到
return i - j;//这里可以返回i-m,我觉写i-m更好理解一点,这里i遍历完,是在haystack中最后一个字符且和needle匹配的索引,索引要知道起始索引,减去要匹配字符串的长度m即可
} else {// 未找到
i -= j - 1;//等价于i=i-j+1,也就是起始位置右移了一下
j = 0;
}
}
return -1;
}
public static void main(String[] args) {
Solution s = new Solution();
s.strStr("aasadbutsad","sad");
}
}
KMP基础
KMP的经典思想就是:当出现字符串不匹配时,可以记录一部分之前已经匹配的文本内容,利用这些信息避免从头再去做匹配。
备考软件设计师的时候遇到过KMP,只是会做选择题,没懂。
next数组就是一个前缀表(prefix table)。前缀表是用来回退的,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配。
要在文本串:aabaabaafa 中查找是否出现过一个模式串:aabaaf。
给定一个非空的字符串 s
,检查是否可以通过由它的一个子串重复多次构成。
示例 1:
输入: s = "abab"
输出: true
解释: 可由子串 "ab" 重复两次构成。
示例 2:
输入: s = "aba"
输出: false
示例 3:
输入: s = "abcabcabcabc"
输出: true
解释: 可由子串 "abc" 重复四次构成。 (或子串 "abcabc" 重复两次构成。)
提示:
1 <= s.length <= 104
s
由小写英文字母组成教程:https://programmercarl.com/0459.%E9%87%8D%E5%A4%8D%E7%9A%84%E5%AD%90%E5%AD%97%E7%AC%A6%E4%B8%B2.html
思路:
复杂度分析:
时间复杂度: O ( l e n ) O(len) O(len)
空间复杂度: O ( l e n ) O(len) O(len),len是字符串的长度
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 数组过程,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;
}
}