You are given a string S consisting of N characters and an integer K. You can modify string S by removing any substring of it. A substring is defined as a contiguous segment of a string.
The goal is to find the shortest substring of S that, after removal, leaves S containing exactly K different characters.
Write a function:
def solution(S, K)
that, given a non-empty string S consisting of N characters and an integer K, returns the length of the shortest substring that can be removed. If there is no such substring, your function should return −1.
Examples:
1. Given S = "abaacbca" and K = 2, your function should return 3. After removing substring "cbc", string S will contain exactly two different characters: a and b.
2. Given S = "aabcabc" and K = 1, your function should return 5. After removing "bcabc", string S will contain exactly one character: a.
3. Given S = "zaaaa" and K = 1, your function should return 1. You can remove only one letter: z.
4. Given S = "aaaa" and K = 2, your function should return −1. There is no such substring of S that, after removal, leaves S containing exactly 2 different characters.
Write an efficient algorithm for the following assumptions:
- N is an integer within the range [1..1,000,000];
- string S is made only of lowercase letters (a−z);
- K is an integer within the range [0..26].
def solution(S, K):
N = len(S)
ltor_stats = []
rtol_stats = []
letters = set()
for i, l in enumerate(S):
if l in letters:
continue
else:
ltor_stats.append(Stats(i - 1, letters))
letters = set(letters)
letters.add(l)
ltor_stats.append(Stats(i - 1, letters))
if len(ltor_stats[-1].letters) < K:
return -1
if len(ltor_stats[-1].letters) == K:
return 0
letters = set()
for i, l in enumerate(reversed(S)):
if l in letters:
continue
else:
rtol_stats.append(Stats(N - i - 1, letters))
letters = set(letters)
letters.add(l)
rtol_stats.append(Stats(N - i - 1, letters))
seen = set()
lenghts = []
def examine_substrings(lindex, rindex):
lstats = ltor_stats[lindex]
rstats = rtol_stats[rindex]
seen.add((lindex, rindex))
union = lstats.letters.union(rstats.letters)
length = rstats.index - lstats.index
if len(union) == K:
lenghts.append(length)
if lindex + 1 < len(ltor_stats) and len(ltor_stats[lindex + 1].letters) <= K:
if (lindex + 1, rindex) not in seen:
examine_substrings(lindex + 1, rindex)
if rindex + 1 < len(rtol_stats) and len(rtol_stats[rindex + 1].letters) <= K:
if (lindex, rindex + 1) not in seen:
examine_substrings(lindex, rindex + 1)
examine_substrings(0, 0)
return min(lenghts)
def solution(S, K):
N = len(S)
ltor_stats = []
rtol_stats = []
letters = set()
for i, l in enumerate(S):
if l in letters:
continue
else:
ltor_stats.append(Stats(i - 1, letters))
letters = set(letters)
letters.add(l)
ltor_stats.append(Stats(i - 1, letters))
if len(ltor_stats[-1].letters) < K:
return -1
if len(ltor_stats[-1].letters) == K:
return 0
letters = set()
for i, l in enumerate(reversed(S)):
if l in letters:
continue
else:
rtol_stats.append(Stats(N - i - 1, letters))
letters = set(letters)
letters.add(l)
rtol_stats.append(Stats(N - i - 1, letters))
seen = set()
lenghts = []
def examine_substrings(lindex, rindex):
lstats = ltor_stats[lindex]
rstats = rtol_stats[rindex]
seen.add((lindex, rindex))
union = lstats.letters.union(rstats.letters)
length = rstats.index - lstats.index
if len(union) == K:
lenghts.append(length)
if lindex + 1 < len(ltor_stats) and len(ltor_stats[lindex + 1].letters) <= K:
if (lindex + 1, rindex) not in seen:
examine_substrings(lindex + 1, rindex)
if rindex + 1 < len(rtol_stats) and len(rtol_stats[rindex + 1].letters) <= K:
if (lindex, rindex + 1) not in seen:
examine_substrings(lindex, rindex + 1)
examine_substrings(0, 0)
return min(lenghts)
def solution(S, K):
N = len(S)
ltor_stats = []
rtol_stats = []
letters = set()
for i, l in enumerate(S):
if l in letters:
continue
else:
ltor_stats.append(Stats(i - 1, letters))
letters = set(letters)
letters.add(l)
ltor_stats.append(Stats(i - 1, letters))
if len(ltor_stats[-1].letters) < K:
return -1
if len(ltor_stats[-1].letters) == K:
return 0
letters = set()
for i, l in enumerate(reversed(S)):
if l in letters:
continue
else:
rtol_stats.append(Stats(N - i - 1, letters))
letters = set(letters)
letters.add(l)
rtol_stats.append(Stats(N - i - 1, letters))
seen = set()
lenghts = []
def examine_substrings(lindex, rindex):
lstats = ltor_stats[lindex]
rstats = rtol_stats[rindex]
seen.add((lindex, rindex))
union = lstats.letters.union(rstats.letters)
length = rstats.index - lstats.index
if len(union) == K:
lenghts.append(length)
if lindex + 1 < len(ltor_stats) and len(ltor_stats[lindex + 1].letters) <= K:
if (lindex + 1, rindex) not in seen:
examine_substrings(lindex + 1, rindex)
if rindex + 1 < len(rtol_stats) and len(rtol_stats[rindex + 1].letters) <= K:
if (lindex, rindex + 1) not in seen:
examine_substrings(lindex, rindex + 1)
examine_substrings(0, 0)
return min(lenghts)
Traceback (most recent call last): File "exec.py", line 127, in <module> main() File "exec.py", line 89, in main result = solution( S, K ) File "/tmp/solution.py", line 11, in solution ltor_stats.append(Stats(i - 1, letters)) NameError: name 'Stats' is not defined
Traceback (most recent call last): File "exec.py", line 127, in <module> main() File "exec.py", line 89, in main result = solution( S, K ) File "/tmp/solution.py", line 11, in solution ltor_stats.append(Stats(i - 1, letters)) NameError: name 'Stats' is not defined
Traceback (most recent call last): File "exec.py", line 127, in <module> main() File "exec.py", line 89, in main result = solution( S, K ) File "/tmp/solution.py", line 11, in solution ltor_stats.append(Stats(i - 1, letters)) NameError: name 'Stats' is not defined
Traceback (most recent call last): File "exec.py", line 127, in <module> main() File "exec.py", line 89, in main result = solution( S, K ) File "/tmp/solution.py", line 11, in solution ltor_stats.append(Stats(i - 1, letters)) NameError: name 'Stats' is not defined
from collections import namedtuple
Stats = namedtuple('Stats', ['index', 'letters'])
def solution(S, K):
N = len(S)
ltor_stats = []
rtol_stats = []
letters = set()
for i, l in enumerate(S):
if l in letters:
continue
else:
ltor_stats.append(Stats(i - 1, letters))
letters = set(letters)
letters.add(l)
ltor_stats.append(Stats(i - 1, letters))
if len(ltor_stats[-1].letters) < K:
return -1
if len(ltor_stats[-1].letters) == K:
return 0
letters = set()
for i, l in enumerate(reversed(S)):
if l in letters:
continue
else:
rtol_stats.append(Stats(N - i - 1, letters))
letters = set(letters)
letters.add(l)
rtol_stats.append(Stats(N - i - 1, letters))
seen = set()
lenghts = []
def examine_substrings(lindex, rindex):
lstats = ltor_stats[lindex]
rstats = rtol_stats[rindex]
seen.add((lindex, rindex))
union = lstats.letters.union(rstats.letters)
length = rstats.index - lstats.index
if len(union) == K:
lenghts.append(length)
if lindex + 1 < len(ltor_stats) and len(ltor_stats[lindex + 1].letters) <= K:
if (lindex + 1, rindex) not in seen:
examine_substrings(lindex + 1, rindex)
if rindex + 1 < len(rtol_stats) and len(rtol_stats[rindex + 1].letters) <= K:
if (lindex, rindex + 1) not in seen:
examine_substrings(lindex, rindex + 1)
examine_substrings(0, 0)
return min(lenghts)
from collections import namedtuple
Stats = namedtuple('Stats', ['index', 'letters'])
def solution(S, K):
N = len(S)
ltor_stats = []
rtol_stats = []
letters = set()
for i, l in enumerate(S):
if l in letters:
continue
else:
ltor_stats.append(Stats(i - 1, letters))
letters = set(letters)
letters.add(l)
ltor_stats.append(Stats(i - 1, letters))
if len(ltor_stats[-1].letters) < K:
return -1
if len(ltor_stats[-1].letters) == K:
return 0
letters = set()
for i, l in enumerate(reversed(S)):
if l in letters:
continue
else:
rtol_stats.append(Stats(N - i - 1, letters))
letters = set(letters)
letters.add(l)
rtol_stats.append(Stats(N - i - 1, letters))
seen = set()
lenghts = []
def examine_substrings(lindex, rindex):
lstats = ltor_stats[lindex]
rstats = rtol_stats[rindex]
seen.add((lindex, rindex))
union = lstats.letters.union(rstats.letters)
length = rstats.index - lstats.index
if len(union) == K:
lenghts.append(length)
if lindex + 1 < len(ltor_stats) and len(ltor_stats[lindex + 1].letters) <= K:
if (lindex + 1, rindex) not in seen:
examine_substrings(lindex + 1, rindex)
if rindex + 1 < len(rtol_stats) and len(rtol_stats[rindex + 1].letters) <= K:
if (lindex, rindex + 1) not in seen:
examine_substrings(lindex, rindex + 1)
examine_substrings(0, 0)
return min(lenghts)
from collections import namedtuple
Stats = namedtuple('Stats', ['index', 'letters'])
def solution(S, K):
N = len(S)
ltor_stats = []
rtol_stats = []
letters = set()
for i, l in enumerate(S):
if l in letters:
continue
else:
ltor_stats.append(Stats(i - 1, letters))
letters = set(letters)
letters.add(l)
ltor_stats.append(Stats(i - 1, letters))
if len(ltor_stats[-1].letters) < K:
return -1
if len(ltor_stats[-1].letters) == K:
return 0
letters = set()
for i, l in enumerate(reversed(S)):
if l in letters:
continue
else:
rtol_stats.append(Stats(N - i - 1, letters))
letters = set(letters)
letters.add(l)
rtol_stats.append(Stats(N - i - 1, letters))
seen = set()
lenghts = []
def examine_substrings(lindex, rindex):
lstats = ltor_stats[lindex]
rstats = rtol_stats[rindex]
seen.add((lindex, rindex))
union = lstats.letters.union(rstats.letters)
length = rstats.index - lstats.index
if len(union) == K:
lenghts.append(length)
if lindex + 1 < len(ltor_stats) and len(ltor_stats[lindex + 1].letters) <= K:
if (lindex + 1, rindex) not in seen:
examine_substrings(lindex + 1, rindex)
if rindex + 1 < len(rtol_stats) and len(rtol_stats[rindex + 1].letters) <= K:
if (lindex, rindex + 1) not in seen:
examine_substrings(lindex, rindex + 1)
examine_substrings(0, 0)
return min(lenghts)
from collections import namedtuple
Stats = namedtuple('Stats', ['index', 'letters'])
def solution(S, K):
N = len(S)
ltor_stats = []
rtol_stats = []
letters = set()
for i, l in enumerate(S):
if l in letters:
continue
else:
ltor_stats.append(Stats(i - 1, letters))
letters = set(letters)
letters.add(l)
ltor_stats.append(Stats(i - 1, letters))
if len(ltor_stats[-1].letters) < K:
return -1
if len(ltor_stats[-1].letters) == K:
return 0
letters = set()
for i, l in enumerate(reversed(S)):
if l in letters:
continue
else:
rtol_stats.append(Stats(N - i - 1, letters))
letters = set(letters)
letters.add(l)
rtol_stats.append(Stats(N - i - 1, letters))
seen = set()
lenghts = []
def examine_substrings(lindex, rindex):
lstats = ltor_stats[lindex]
rstats = rtol_stats[rindex]
seen.add((lindex, rindex))
union = lstats.letters.union(rstats.letters)
length = rstats.index - lstats.index
if len(union) == K:
lenghts.append(length)
if lindex + 1 < len(ltor_stats) and len(ltor_stats[lindex + 1].letters) <= K:
if (lindex + 1, rindex) not in seen:
examine_substrings(lindex + 1, rindex)
if rindex + 1 < len(rtol_stats) and len(rtol_stats[rindex + 1].letters) <= K:
if (lindex, rindex + 1) not in seen:
examine_substrings(lindex, rindex + 1)
examine_substrings(0, 0)
return min(lenghts)
The solution obtained perfect score.