KMP
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstdlib> 5 #include <cstring> 6 #include <string> 7 #include <deque> 8 #include <vector> 9 #include <set> 10 #include <map> 11 #include <cmath> 12 using namespace std; 13 #define ll long long 14 #define N 100009 15 #define gep(i,a,b) for(int i=a;i<=b;i++) 16 #define gep1(i,a,b) for(int i=a;i>=b;i--) 17 #define gepp(i,a,b) for(ll i=a;i<=b;i++) 18 #define gepp1(i,a,b) for(ll i=a;i>=b;i--) 19 #define mem(a,b) memset(a,b,sizeof(a)) 20 #define ph push_back 21 #define lowbit(x) x&(-x) 22 #define P pair<int,bool> 23 int c[100]; 24 char p[100]; 25 void get(){ 26 mem(c,0); 27 int i=0,j=-1; 28 c[0]=-1; 29 while(p[i]){ 30 if(j==-1||p[i]==p[j]){ 31 c[++i]=++j; 32 } 33 else 34 {j=c[j]; 35 } 36 } 37 /* 38 for(int i=0;i<=strlen(p);i++){//有== 39 printf("%d ",c[i]); 40 } 41 42 azcaz 43 -1 0 0 0 1 2 44 c[i]: p[0:i)中前缀和后缀的最长公共在前缀的右边界(+1)
例如:
azcazaz
a -1
az 0
azc 0
azca 0
azcaz 1 :在azca中前缀a后缀 a 为最长公共,而a在前缀的右边界+1的索引为1(z的位置)
azcaza 2 : 在azcaza中前缀az后缀az 为最长公共 ,而az在前缀的右边界+1的索引为2(c的位置)
azcazaz 1 :在azcazaz中前缀a后缀a为最长公共,而a在前缀的右边界+1的索引为1(z的位置)
azcazaz_ 2 :在azcazaz中前缀az后缀az为最长公共,而az在前缀的右边界+1的索引为2(c的位置) 45 printf("\n"); 46 */ 47 48 }
p在s中第一次出现的位置 49 int kmp(){ 50 int i,j; 51 i=j=0; 52 get(); 53 while(i<n&&j<m){ 54 if(j==-1||s[i]==p[j]){ 55 i++,j++; 56 } 57 else 58 { 59 j=c[j]; 60 } 61 if(j==m) 62 { 63 return i-m; 64 } 65 } 66 return -1; 67 /* 68 1 2 1 2 3 1 2 3 1 3 2 1 2//初始下标为0 69 1 2 3 1 3 70 5 71 1 2 1 2 3 1 2 3 1 3 2 1 2 72 1 2 3 2 1 73 -1 74 */ 75 }
p在s中出现的次数 不同p可有交集 76 int kmp(){ 77 int lens=strlen(s); 78 int lenp=strlen(p); 79 int i=0,j=0; 80 int ans=0; 81 get(); 82 while(i<lens&&j<lenp){ 83 if(j==-1||s[i]==p[j]){ 84 i++; 85 j++; 86 87 } 88 else 89 { 90 j=c[j]; 91 } 92 if(j==lenp){ 93 ans++; 94 j=c[j]; 95 } 96 97 } 98 return ans; 99 /* 100 AZA 101 AZAZAZA 102 3 103 */ 104 }
p在s中出现的次数,不同p无交集 105 int kmp(){ 106 int lens=strlen(s); 107 int lenp=strlen(p); 108 int i=0,j=0; 109 int ans=0; 110 get(); 111 while(i<lens&&j<lenp){ 112 if(j==-1||s[i]==p[j]){ 113 i++; 114 j++; 115 116 } 117 else 118 { 119 j=c[j]; 120 } 121 if(j==lenp){ 122 ans++; 123 j=0; 124 } 125 126 } 127 return ans; 128 /* 129 aaaaaa 130 aa 131 3 132 */ 133 134 } 135 字符串后面添加元素令字符串为周期字符串 136 while(t--) 137 { 138 scanf("%s",p); 139 get(); 140 int len2=strlen(p);
abcab x:3
abcabc x:3 当然循环节也可以为6 141 int x=len2-a[len2];//最小循环节长度 142 if(x==len2) 143 { 144 printf("%d\n",len2);//abcde:5 再加abcde 才可以构成循环 145 } 146 else if (len2%x==0)//aaa :1 已经可以构成循环了 147 { 148 printf("0\n"); 149 } 150 else 151 { 152 printf("%d\n",x-len2%x);// abca : 3 再加bc才可以构成循环 153 } 154 }
求s的最长前缀回文串
ababade :ababa
让p=s的反转
s = s+'#'+p
利用kmp 得到num=c[s.length]
原s[0:num) 为s的最长前缀回文串
在让sp = 原s[num:s.length)
sp的反转+原s--》回文串
即在原s前面加上sp的反转让原s变为回文串
leetcode.cn/problems/shortest-palindrome/description/
/**
* @param {string} s
* @return {string}
*/
var c = new Array(500007).fill(0);
function get(s){
let i =0,j=-1;
c[0] =-1;
while(Boolean(s[i])==true){
if(j==-1||s[i]==s[j]) {
c[++i] =++j;
}else{
j =c[j];
}
}
}
function revers(s){
return s.split("").reverse().join("");
}
var shortestPalindrome = function(s) {
let tmp =s;
let p = revers(s);
s+='#';
s+=p;
get(s);
let num = c[s.length];
console.log(num)
let s1 = revers(tmp.substring(num));
return s1+tmp;
};