给你一个文本串 T ,一个非空模板串 S ,问 S 在 T 中出现了多少次
数据范围:
要求:空间复杂度
,时间复杂度 %2Blen(T)))
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 计算模板串S在文本串T中出现了多少次
* @param S string字符串 模板串
* @param T string字符串 文本串
* @return int整型
*/
int kmp(char* S, char* T )
{
// write code here
int a,i,j,n=0;
a=strlen(S);
for(i=0;T[i]!='\0';i++)
{
for(j=0;j<a;j++)
{
if(S[j]!=T[i+j])
{
break;
}
}
if(j>=a)
{
n++;
}
}
return n;
}
public class Solution {
public int kmp (String S, String T) {
int res = 0;
int[] next = new int[S.length()];
getNext(next, S);
int j = 0;
int i = 0;
while (i < T.length()) {
// 退到头或相等,i指针往后
if (j == 0 || T.charAt(i) == S.charAt(j)){
i++;
j++;
}
else { // j回退,防止溢出
if (j == 0) j = 0;
else j = next[j - 1];
}
if (j == S.length()){ // 找到一个子串,j回退
res++;
j = next[j - 1];
}
}
return res;
}
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(i) != S.charAt(j))
j = next[j - 1];
// 前缀相同时,更新前缀指针和next数组
if (S.charAt(i) == S.charAt(j)) {
j++;
next[i] = j;
}
}
}
} 人家三个学者提出来的算法,没提前学过或专门学过,基本没人能直接写出来。完整学过理解之后才能模仿实现,这种题也能算中等题?。。
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 计算模板串S在文本串T中出现了多少次
* @param S string字符串 模板串
* @param T string字符串 文本串
* @return int整型
*/
function kmp( S , T ) {
var index = T.indexOf(S);
var count = 0;
while(index > -1) {
count++;
index = T.indexOf(S, index + 1);
}
return count;
}
module.exports = {
kmp : kmp
}; class Solution: def kmp(self , S , T ): # kmp算法参考leetcode 28 # 不同于kmp,这里还需统计匹配的次数 m = len(T) n = len(S) # 创建next数组 nex = [0] * n count = 0 j = 0 # 计算next数组 for i in range(1, n): while j > 0 and S[j] != S[i]: j = nex[j-1] if S[j] == S[i]: j += 1 nex[i] = j # kmp字符串匹配 j = 0 for i in range(m): while j > 0 and S[j] != T[i]: j = nex[j-1] if S[j] == T[i]: j += 1 # 判断是否完成完整匹配 if j == n: count += 1 j = nex[j-1] # 返回出现个数 return count
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 计算模板串S在文本串T中出现了多少次
* @param S string字符串 模板串
* @param T string字符串 文本串
* @return int整型
*/
public int kmp (String S, String T) {
return find(T,S);
}
int find(String source,String pattern){
int n1=source.length();
int n2=pattern.length();
char []par=pattern.toCharArray();
char[]sour=source.toCharArray();
int[]next=new int[n2];
int k=-1;
next[0]=-1;
//构建next数组,其中第next[i]表示par模式串数组中最长公共前缀后缀的前缀结束的下标
// par="aabaac" next[0]=-1 next[1]=1 next[2]=-1 next[3]=1 next[4]=1 next[5]=-1
for(int i=1;i<n2;i++){
while(k!=-1&&par[k+1]!=par[i])k=next[k];
if(par[k+1]==par[i])k++;
next[i]=k;
}
k=-1;
int ans=0;
for(int j=0;j<n1;j++){
//如果匹配 j++,k++
if(sour[j]==par[k+1])k++;
else{
//不匹配则在模式串中,继续向前搜索
//比如pattern aabaac
//待查找的串 aaeefaagef
// aeefaagef aeefaagef
// aabaac aabaac
// |该位置不匹配 next[1]=0|
while(k!=-1&&par[k+1]!=sour[j])k=next[k];
}
if(k==n2-1){
int pre=j-pattern.length()+2;
ans++;
j=pre;
k=-1;
}
}
return ans;
}
} class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 计算模板串S在文本串T中出现了多少次
* @param S string字符串 模板串
* @param T string字符串 文本串
* @return int整型
*/
vector<int> getNextArray(string &T)
{
if(T.size()==1) return {-1};//0位置的最长前后缀匹配长度是1。
vector<int> next(T.size());
next[0]=-1;
next[1]=0;
int i=2;//下标位置
int cn=0;//和i-1位置进行比较的下标位置(因为i=2,所以i-1=1,所以cn=0)
while(i<T.size())
{
if(T[i-1]==T[cn])
{
next[i++]=++cn;
}
else if(cn>0)
{
cn=next[cn];
}
else//cn=0,没法再往前跳了,没法匹配,需要i++
{
next[i++]=0;
}
}
return next;
}
int kmp(string S, string T) {
// write code here
int res=0;
if(S.size()<T.size())
swap(S,T);
vector<int> next=getNextArray(T);//获取next数组
int i1=0;//S的遍历下标
int i2=0;//T的遍历下标
while(i1<S.size())
{
if(S[i1]==T[i2])
{
if(i2==T.size()-1)//产生了一次匹配,i2回到开头
{
res++;
//将i2前缀和i1的后缀对齐,i1在后缀的下一个位置。
i2=next[i2];//i2在前缀的下一个位置。
}
else
{
i1++;
i2++;
}
}
//不匹配,i2往前跳
else if(i2>0)//i2还没来到了0位置,可以往前跳最长前缀的下一个位置
{
i2=next[i2];
}
else//i2已经来到了0位置,没法继续往前跳了,i1需要++
{
i1++;
}
}
return res;
}
}; class Solution {
public:
int kmp(string S, string T) {
// write code here
int ans=0;//记录出现次数
//先求next数组-前缀表
int next[S.size()];
next[0]=0;
int j=0;
for(int i=1;i<S.size();i++){
//前后缀不相同时
while(j>0&&S[i]!=S[j]){
j=next[j-1];//回退
}
//前后缀相同时
if(S[i]==S[j]){
j++;
next[i]=j;
}
}
//看模板串在文本串出现了几次
j=0;
for(int i=0;i<T.size();i++){
while(j>0&&T[i]!=S[j]){
j=next[j-1];//回退
}
if(T[i]==S[j]) j++;
if(j==S.size()){//j==S.size():说明已经遍历完找到一个了
ans++;
j=next[j-1];
}
}
return ans;
}
}; function kmp(S, T) {
if (!S || !T || T.length < S.length) return 0;
const next = getNext(S);
return getCount(next, S, T);
}
function getNext(needle) {
const next = Array(needle.length).fill(0);
for (let i = 1, j = 0; i < needle.length; ++i) {
while (j > 0 && needle[i] !== needle[j]) j = next[j - 1];
if (needle[i] === needle[j]) j++;
next[i] = j;
}
return next;
}
function getCount(next, needle, haystack) {
let count = 0;
for (let i = 0, j = 0; i < haystack.length; i++) {
while (j > 0 && haystack[i] !== needle[j]) j = next[j - 1];
if (haystack[i] === needle[j]) ++j;
if (j === needle.length) {
count++;
j = next[j - 1];
}
}
return count;
} public int kmp (String S, String T) {
final int sLength = S.length();
final AtomicInteger count = new AtomicInteger();
Queue<Character> sQueue = new LinkedList<>();
Queue<Character> tQueue = new LinkedList<>();
IntStream.range(0, sLength).forEach(index -> {
sQueue.offer(S.charAt(index));
tQueue.offer(T.charAt(index));
});
if (sQueue.hashCode() == tQueue.hashCode()) {
count.getAndIncrement();
}
IntStream.range(0, T.length()-sLength).forEach(index -> {
tQueue.poll();
tQueue.offer(T.charAt(index + sLength));
if (sQueue.hashCode() == tQueue.hashCode()) {
count.getAndIncrement();
}
});
return count.get();
} class Solution: def kmp(self, S: str, T: str) -> int: # write code here # 运行超时 len_s = len(S) len_t = len(T) res = 0 for i in range(len_t - len_s + 1): if S == T[i : i + len_s]: res +=1 return res
import java.util.*;
public class Solution {
public int kmp(String S, String T) {
int M = S.length();
int N = T.length();
// 创建lps[]数组,保存模式串的前缀函数
int[] lps = LPS(S);
// 初始化两个指针i和j,分别指向文本T和模式串S的当前位置
int i = 0;
int j = 0;
// 初始化计数器count,用于记录模式串S在文本T中出现的次数
int count = 0;
// 遍历文本T,直到指针i到达文本的末尾
while (i < N) {
// 如果模式串S的当前字符与文本T的当前字符相同,则两个指针都向前移动
if (S.charAt(j) == T.charAt(i)) {
j++;
i++;
}
// 如果模式串S已经完全匹配,则增加计数器,并根据lps数组将模式串的指针j回溯到合适的位置
if (j == M) {
count++;
j = lps[j - 1];
} else if (i < N && S.charAt(j) != T.charAt(i)) {
// 如果当前字符不匹配,且模式串的指针j不为0,则根据lps数组将模式串的指针j回溯
if (j != 0)
j = lps[j - 1];
// 如果模式串的指针j为0,则只能将文本的指针i向前移动
else
i = i + 1;
}
}
return count;
}
// 定义一个私有静态方法,用于计算模式串的前缀函数数组lps[]
private static int[] LPS(String pattern) {
// 初始化lps数组,长度与模式串相同
int[] lps = new int[pattern.length()];
// 初始化len为0,用于记录前缀的长度
int len = 0;
// 初始化i为1,因为lps[0]总是为0
int i = 1;
// lps[0]设置为0,因为模式串的第一个字符总是前缀
lps[0] = 0;
// 遍历模式串,计算每个位置的前缀长度
while (i < pattern.length()) {
// 如果当前字符与前缀的最后一个字符相同,则更新len和lps[i]
if (pattern.charAt(i) == pattern.charAt(len)) {
len++;
lps[i] = len;
i++;
} else {
// 如果当前字符与前缀的最后一个字符不同,且len不为0,则根据lps数组回溯len
if (len != 0) {
len = lps[len - 1];
} else {
// 如果len为0,则更新lps[i]为0,并向前移动i
lps[i] = 0;
i++;
}
}
}
return lps;
}
} /**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 计算模板串S在文本串T中出现了多少次
* @param S string字符串 模板串
* @param T string字符串 文本串
* @return int整型
*/
#include <string.h>
int ne[100000];
void getNext(char* a, int next[])
{
int j = 0;
next[0] = 0;
for(int i = 1; i < strlen(a); i++)
{
while(j > 0 && a[i] != a[j])
{
j = next[j - 1]; //回到前一个,相当于自身做了一次kmp
}
if(a[i] == a[j])
{
j++;
}
next[i] = j;
}
}
int kmp(char* S, char* T ) {
// write code here
int i = 0 , j = 0, count = 0;
int slen = strlen(S);
int tlen = strlen(T);
getNext(S, ne);
for(i = 0; i < tlen; i++)
{
if(j == 0 && tlen - i < slen)
break;
while(j > 0 && T[i] != S[j])
{
j = ne[j - 1];
}
if(T[i] == S[j])
{
j++;
}
if(j == slen)
{
count++;
j = ne[j - 1];
}
}
return count;
}
还是跑不完,只能跑5组测试用例,数一大还是超时,还望老哥们赐教
// 参考B站左程云大佬的KMP算法讲解
public int kmp (String S, String T) {
// write code here
char []s1 = S.toCharArray();
char []s2 = T.toCharArray();
int n = s1.length, m = s2.length;
if (n > m || m == 0) return 0;
int cnt = 0;
int x = 0, y = 0;
int index = 0;
int []next = nextArray(s1, n);
while (x < m) {
if (y == n-1&&s1[y] == s2[x]) {
cnt++;
y=next[y];
}
if (s1[y] == s2[x]) {
x++;
y++;
} else if (y == 0) {
x++;
} else {
y = next[y];
}
}
return cnt;
}
/**
得到next数组
*/
public int[] nextArray(char []s, int m) {
if (m == 1) {
return new int[] {-1};
}
int []next = new int[m];
next[0] = -1;
next[1] = 0;
int i = 2, cn = 0;
while (i < m) {
if (s[i - 1] == s[cn]) {
next[i++] = ++cn;
} else if (cn > 0) {
cn = next[cn];
} else {
next[i++] = 0;
}
}
return next;
} // 超时算法
public int kmp (String S, String T) {
// write code here
int ls=S.length() ,lt=T.length() ,res=0;
for(int i=0;i+ls<=lt;i++){
if(S.equals(T.substring(i,i+ls))){
res++;
}
}
return res;
}