双指针
字符串
二分查找
字符串匹配
哈希函数
滚动哈希
题目描述
给你一个下标从 0 开始的字符串 s
、字符串 a
、字符串 b
和一个整数 k
。
如果下标 i
满足以下条件,则认为它是一个 美丽下标 :
0 <= i <= s.length - a.length
s[i..(i + a.length - 1)] == a
存在下标 j
使得:
0 <= j <= s.length - b.length
s[j..(j + b.length - 1)] == b
|j - i| <= k
以数组形式按 从小到大排序 返回美丽下标。
示例 1:
输入: s = "isawsquirrelnearmysquirrelhouseohmy", a = "my", b = "squirrel", k = 15
输出: [16,33]
解释: 存在 2 个美丽下标:[16,33]。
- 下标 16 是美丽下标,因为 s[16..17] == "my" ,且存在下标 4 ,满足 s[4..11] == "squirrel" 且 |16 - 4| <= 15 。
- 下标 33 是美丽下标,因为 s[33..34] == "my" ,且存在下标 18 ,满足 s[18..25] == "squirrel" 且 |33 - 18| <= 15 。
因此返回 [16,33] 作为结果。
示例 2:
输入: s = "abcd", a = "a", b = "a", k = 4
输出: [0]
解释: 存在 1 个美丽下标:[0]。
- 下标 0 是美丽下标,因为 s[0..0] == "a" ,且存在下标 0 ,满足 s[0..0] == "a" 且 |0 - 0| <= 4 。
因此返回 [0] 作为结果。
提示:
1 <= k <= s.length <= 5 * 105
1 <= a.length, b.length <= 5 * 105
s
、a
、和 b
只包含小写英文字母。
解法
方法一
Python3 Java C++ Go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 class Solution :
def beautifulIndices ( self , s : str , a : str , b : str , k : int ) -> List [ int ]:
def build_prefix_function ( pattern ):
prefix_function = [ 0 ] * len ( pattern )
j = 0
for i in range ( 1 , len ( pattern )):
while j > 0 and pattern [ i ] != pattern [ j ]:
j = prefix_function [ j - 1 ]
if pattern [ i ] == pattern [ j ]:
j += 1
prefix_function [ i ] = j
return prefix_function
def kmp_search ( pattern , text , prefix_function ):
occurrences = []
j = 0
for i in range ( len ( text )):
while j > 0 and text [ i ] != pattern [ j ]:
j = prefix_function [ j - 1 ]
if text [ i ] == pattern [ j ]:
j += 1
if j == len ( pattern ):
occurrences . append ( i - j + 1 )
j = prefix_function [ j - 1 ]
return occurrences
prefix_a = build_prefix_function ( a )
prefix_b = build_prefix_function ( b )
resa = kmp_search ( a , s , prefix_a )
resb = kmp_search ( b , s , prefix_b )
res = []
print ( resa , resb )
i = 0
j = 0
while i < len ( resa ):
while j < len ( resb ):
if abs ( resb [ j ] - resa [ i ]) <= k :
res . append ( resa [ i ])
break
elif j + 1 < len ( resb ) and abs ( resb [ j + 1 ] - resa [ i ]) < abs (
resb [ j ] - resa [ i ]
):
j += 1
else :
break
i += 1
return res
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99 public class Solution {
public void computeLPS ( String pattern , int [] lps ) {
int M = pattern . length ();
int len = 0 ;
lps [ 0 ] = 0 ;
int i = 1 ;
while ( i < M ) {
if ( pattern . charAt ( i ) == pattern . charAt ( len )) {
len ++ ;
lps [ i ] = len ;
i ++ ;
} else {
if ( len != 0 ) {
len = lps [ len - 1 ] ;
} else {
lps [ i ] = 0 ;
i ++ ;
}
}
}
}
public List < Integer > KMP_codestorywithMIK ( String pat , String txt ) {
int N = txt . length ();
int M = pat . length ();
List < Integer > result = new ArrayList <> ();
int [] lps = new int [ M ] ;
computeLPS ( pat , lps );
int i = 0 ; // Index for text
int j = 0 ; // Index for pattern
while ( i < N ) {
if ( pat . charAt ( j ) == txt . charAt ( i )) {
i ++ ;
j ++ ;
}
if ( j == M ) {
result . add ( i - j ); // Pattern found at index i-j+1 (If you have to return 1 Based
// indexing, that's why added + 1)
j = lps [ j - 1 ] ;
} else if ( i < N && pat . charAt ( j ) != txt . charAt ( i )) {
if ( j != 0 ) {
j = lps [ j - 1 ] ;
} else {
i ++ ;
}
}
}
return result ;
}
private int lowerBound ( List < Integer > list , int target ) {
int left = 0 , right = list . size () - 1 , result = list . size ();
while ( left <= right ) {
int mid = left + ( right - left ) / 2 ;
if ( list . get ( mid ) >= target ) {
result = mid ;
right = mid - 1 ;
} else {
left = mid + 1 ;
}
}
return result ;
}
public List < Integer > beautifulIndices ( String s , String a , String b , int k ) {
int n = s . length ();
List < Integer > i_indices = KMP_codestorywithMIK ( a , s );
List < Integer > j_indices = KMP_codestorywithMIK ( b , s );
List < Integer > result = new ArrayList <> ();
for ( int i : i_indices ) {
int left_limit = Math . max ( 0 , i - k ); // To avoid out of bound -> I used max(0, i-k)
int right_limit
= Math . min ( n - 1 , i + k ); // To avoid out of bound -> I used min(n-1, i+k)
int lowerBoundIndex = lowerBound ( j_indices , left_limit );
if ( lowerBoundIndex < j_indices . size ()
&& j_indices . get ( lowerBoundIndex ) <= right_limit ) {
result . add ( i );
}
}
return result ;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 class Solution {
public :
vector < int > beautifulIndices ( string s , string patternA , string patternB , int k ) {
vector < int > beautifulIndicesA = kmpSearch ( s , patternA );
vector < int > beautifulIndicesB = kmpSearch ( s , patternB );
sort ( beautifulIndicesB . begin (), beautifulIndicesB . end ());
vector < int > result ;
for ( int indexA : beautifulIndicesA ) {
int left = lower_bound ( beautifulIndicesB . begin (), beautifulIndicesB . end (), indexA - k ) - beautifulIndicesB . begin ();
int right = lower_bound ( beautifulIndicesB . begin (), beautifulIndicesB . end (), indexA + k + patternB . length ()) - beautifulIndicesB . begin ();
left = ( left >= 0 ) ? left : - ( left + 1 );
right = ( right >= 0 ) ? right : - ( right + 1 );
for ( int indexB = left ; indexB < right ; indexB ++ ) {
if ( abs ( beautifulIndicesB [ indexB ] - indexA ) <= k ) {
result . push_back ( indexA );
break ;
}
}
}
return result ;
}
private :
vector < int > kmpSearch ( string text , string pattern ) {
vector < int > indices ;
vector < int > pi = computePrefixFunction ( pattern );
int q = 0 ;
for ( int i = 0 ; i < text . length (); i ++ ) {
while ( q > 0 && pattern [ q ] != text [ i ]) {
q = pi [ q - 1 ];
}
if ( pattern [ q ] == text [ i ]) {
q ++ ;
}
if ( q == pattern . length ()) {
indices . push_back ( i - q + 1 );
q = pi [ q - 1 ];
}
}
return indices ;
}
vector < int > computePrefixFunction ( string pattern ) {
int m = pattern . length ();
vector < int > pi ( m , 0 );
int k = 0 ;
for ( int q = 1 ; q < m ; q ++ ) {
while ( k > 0 && pattern [ k ] != pattern [ q ]) {
k = pi [ k - 1 ];
}
if ( pattern [ k ] == pattern [ q ]) {
k ++ ;
}
pi [ q ] = k ;
}
return pi ;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83 func beautifulIndices ( s string , a string , b string , k int ) [] int {
s_len := len ( s )
a_len := len ( a )
b_len := len ( b )
final := make ([] int , 0 )
lps_a := make ([] int , a_len )
lps_b := make ([] int , b_len )
a_index := make ([] int , 0 )
b_index := make ([] int , 0 )
var pat func ( lps [] int , s_l int , pattern string )
pat = func ( lps [] int , s_l int , pattern string ) {
l := 0
lps [ 0 ] = 0
i := 1
for i < s_l {
if pattern [ i ] == pattern [ l ] {
l ++
lps [ i ] = l
i ++
} else {
if l != 0 {
l = lps [ l - 1 ]
} else {
lps [ i ] = l
i ++
}
}
}
}
pat ( lps_a , a_len , a )
pat ( lps_b , b_len , b )
var kmp func ( pat string , pat_l int , lps [] int , index * [] int )
kmp = func ( pat string , pat_l int , lps [] int , index * [] int ) {
i := 0
j := 0
for s_len - i >= pat_l - j {
if s [ i ] == pat [ j ] {
i ++
j ++
}
if j == pat_l {
* index = append ( * index , i - pat_l )
j = lps [ j - 1 ]
} else if s [ i ] != pat [ j ] {
if j != 0 {
j = lps [ j - 1 ]
} else {
i ++
}
}
}
}
kmp ( a , a_len , lps_a , & a_index )
kmp ( b , b_len , lps_b , & b_index )
// fmt.Println(a_index, b_index)
i := 0
j := 0
for i < len ( a_index ) && j < len ( b_index ) {
if a_index [ i ] + k >= b_index [ j ] && a_index [ i ] - k <= b_index [ j ] {
final = append ( final , a_index [ i ])
i ++
} else if a_index [ i ] - k > b_index [ j ] {
j ++
} else {
i ++
}
}
return final
}