LeetCode28.找出字符串中第一个匹配项的下标
方法一:常规遍历
基本思路:生成两个指针分别指向两个字符串的头,然后逐个比较,如果相同,两指针都下移,当第二个指针指向了匹配字符串的末尾,那么说明这个字符串就匹配,返回第一个位置。如果没有到达结尾,那么说明不匹配,返回-1。
Java代码如下:
public int strStr(String haystack, String needle) {
int n = haystack.length();
int m = needle.length();
char[] char_a = haystack.toCharArray();
char[] char_b = needle.toCharArray();
for(int i = 0;i <= n - m;i++)
{
int a = i;
int b = 0;
while( b < m && char_a[a] == char_b[b])
{
a++;
b++;
}
if(b == m)
{
return i;
}
}
return -1;
}
方法二:使用KMP算法
基本思路:字符串aabaa的最长相等的前缀 和 后缀字符串是 子字符串aa ,因为找到了最长相等的前缀和后缀,匹配失败的位置是后缀子串的后面,那么我们找到与其相同的前缀的后面重新匹配就可以了。
Java代码如下:
public int strStr_kmp(String haystack, String needle) {
if(needle.length() == 0)
{
return 0;
}
int[] next = new int[needle.length()];
getNext(next,needle);
int j = 0;
for(int i = 0; i < haystack.length(); i++)
{
while(j > 0 && needle.charAt(j) != haystack.charAt(i))
{
j = next[j - 1];
}
if(needle.charAt(j) == haystack.charAt(i))
{
j++;
}
if(j == needle.length())
{
return i - needle.length() + 1;
}
}
return -1;
}
public void getNext(int[] next,String s) {
int j = 0;
next[0] = 0;
for(int i = 1; i < s.length();i++)
{
while(j > 0 && s.charAt(j) != s.charAt(i))
{
j = next[j - 1];
}
if(s.charAt(i) == s.charAt(j))
{
j++;
}
next[i] = j;
}
}
LeetCode 459.重复的字符串
基本思路:数组长度减去最长相同前后缀的长度相当于是第一个周期的长度,也就是一个周期的长度,如果这个周期可以被整除,就说明整个数组就是这个周期的循环。
Java代码如下:
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往后移
j = next[j];
}
if(chars[i] == chars[j+1])
{
// 更新 next 数组的值
j++;
}
next[i] = j;
}
// 最后判断是否是重复的子字符串,这里 next[len] 即代表next数组末尾的值
if(next[len] > 0 && len % (len - next[len]) == 0)
{
return true;
}
return false;
}