Hard
You are given two strings s
and pattern
.
A string x
is called almost equal to y
if you can change at most one character in x
to make it identical to y
.
Return the smallest starting index of a substring in s
that is almost equal to pattern
. If no such index exists, return -1
.
A substring is a contiguous non-empty sequence of characters within a string.
Example 1:
Input: s = “abcdefg”, pattern = “bcdffg”
Output: 1
Explanation:
The substring s[1..6] == "bcdefg"
can be converted to "bcdffg"
by changing s[4]
to "f"
.
Example 2:
Input: s = “ababbababa”, pattern = “bacaba”
Output: 4
Explanation:
The substring s[4..9] == "bababa"
can be converted to "bacaba"
by changing s[6]
to "c"
.
Example 3:
Input: s = “abcd”, pattern = “dba”
Output: -1
Example 4:
Input: s = “dde”, pattern = “d”
Output: 0
Constraints:
1 <= pattern.length < s.length <= 3 * 105
s
and pattern
consist only of lowercase English letters.Follow-up: Could you solve the problem if at most k
consecutive characters can be changed?
import kotlin.math.abs
class Solution {
fun minStartingIndex(s: String, pattern: String): Int {
val n = s.length
var left = 0
var right = 0
val f1 = IntArray(26)
val f2 = IntArray(26)
for (ch in pattern.toCharArray()) {
f2[ch.code - 'a'.code]++
}
while (right < n) {
val ch = s[right]
f1[ch.code - 'a'.code]++
if (right - left + 1 == pattern.length + 1) {
f1[s[left].code - 'a'.code]--
left += 1
}
if (right - left + 1 == pattern.length && check(f1, f2, left, s, pattern)) {
return left
}
right += 1
}
return -1
}
private fun check(f1: IntArray, f2: IntArray, left: Int, s: String, pattern: String): Boolean {
var cnt = 0
for (i in 0..25) {
if (f1[i] != f2[i]) {
if ((abs((f1[i] - f2[i])) > 1) || (abs(f1[i] - f2[i]) != 1 && cnt == 2)) {
return false
}
cnt += 1
}
}
cnt = 0
var start = 0
var end = pattern.length - 1
while (start <= end) {
if (s[start + left] != pattern[start]) {
cnt += 1
}
if (start + left != left + end && s[left + end] != pattern[end]) {
cnt += 1
}
if (cnt >= 2) {
return false
}
start++
end--
}
return true
}
}