You are given a 0-indexed string s, a string a, a string b, and an integer k.
An index i is beautiful if:
0 <= i <= s.length - a.length
s[i..(i + a.length - 1)] == a
There exists an index j such that:
0 <= j <= s.length - b.length
s[j..(j + b.length - 1)] == b
|j - i| <= k
Return the array that contains beautiful indices in sorted order from smallest to largest.
Example 1:
Input: s = "isawsquirrelnearmysquirrelhouseohmy", a = "my", b = "squirrel", k = 15
Output: [16,33]
Explanation: There are 2 beautiful indices: [16,33].
- The index 16 is beautiful as s[16..17] == "my" and there exists an index 4 with s[4..11] == "squirrel" and |16 - 4| <= 15.
- The index 33 is beautiful as s[33..34] == "my" and there exists an index 18 with s[18..25] == "squirrel" and |33 - 18| <= 15.
Thus we return [16,33] as the result.
Example 2:
Input: s = "abcd", a = "a", b = "a", k = 4
Output: [0]
Explanation: There is 1 beautiful index: [0].
- The index 0 is beautiful as s[0..0] == "a" and there exists an index 0 with s[0..0] == "a" and |0 - 0| <= 4.
Thus we return [0] as the result.
Constraints:
1 <= k <= s.length <= 105
1 <= a.length, b.length <= 10
s, a, and b contain only lowercase English letters.
Solutions
Solution 1
Thinking
\(|s| \le 10^5\) and \(|a|,|b| \le 10\), so finding occurrences is cheap, but pairing every \(i\) with every \(j\) is quadratic.
KMP lists all starts of \(a\) and \(b\) in linear time. Both lists are sorted, so each \(i\) only needs a advancing pointer on the \(b\) list to find some \(j\) with \(|i-j| \le k\).
The code builds prefix functions, searches, then walks the two occurrence lists with two pointers.
publicclassSolution{publicvoidcomputeLPS(Stringpattern,int[]lps){intM=pattern.length();intlen=0;lps[0]=0;inti=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++;}}}}publicList<Integer>KMP_codestorywithMIK(Stringpat,Stringtxt){intN=txt.length();intM=pat.length();List<Integer>result=newArrayList<>();int[]lps=newint[M];computeLPS(pat,lps);inti=0;// Index for textintj=0;// Index for patternwhile(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];}elseif(i<N&&pat.charAt(j)!=txt.charAt(i)){if(j!=0){j=lps[j-1];}else{i++;}}}returnresult;}privateintlowerBound(List<Integer>list,inttarget){intleft=0,right=list.size()-1,result=list.size();while(left<=right){intmid=left+(right-left)/2;if(list.get(mid)>=target){result=mid;right=mid-1;}else{left=mid+1;}}returnresult;}publicList<Integer>beautifulIndices(Strings,Stringa,Stringb,intk){intn=s.length();List<Integer>i_indices=KMP_codestorywithMIK(a,s);List<Integer>j_indices=KMP_codestorywithMIK(b,s);List<Integer>result=newArrayList<>();for(inti:i_indices){intleft_limit=Math.max(0,i-k);// To avoid out of bound -> I used max(0, i-k)intright_limit=Math.min(n-1,i+k);// To avoid out of bound -> I used min(n-1, i+k)intlowerBoundIndex=lowerBound(j_indices,left_limit);if(lowerBoundIndex<j_indices.size()&&j_indices.get(lowerBoundIndex)<=right_limit){result.add(i);}}returnresult;}}