Substring repeating character
Source
CheckiO, Long Repeat
Contents
Description
Here you should find the length of the longest substring that consists of the same letter. For example, line “aaabbcaaaa” contains four substrings with the same letters “aaa”, “bb”,”c” and “aaaa”. The last substring is the longest one, which makes it the answer.
Solution sketch 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
_str = 'foooooooooobaaaaaaaar'
curr, longest = 1, 1
for i, c in enumerate(_str):
try:
if c == _str[i + 1]:
curr += 1
else:
if curr > longest:
longest = curr
curr = 1
except IndexError:
pass
assert longest == 10
Solution sketch 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
_str = 'foooooooooobaaaaaaaar'
curr, longest = 1, 1
for i, c in enumerate(_str):
try:
curr = curr + 1 if _str[i + 1] == c else 1
except IndexError:
pass
longest = curr if curr > longest else longest
longest = 0 if not _str else longest
assert longest == 10
My solution
O(n).
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
def solution(s: str = "") -> int:
"""Return length of the longest repetition of a character.
Given a string `s`, return the length of the substring representing
the greatest contiguous repetition of a single character in `s`.
Args:
s: a string
Returns:
An integer representing the longest relevant substring.
Examples:
>>> solution('aaab')
3
>>> solution('abbb')
3
>>> solution('aabbbc')
3
"""
curr = 1
longest = 0 if not s else 1
for i, c in enumerate(s):
try:
curr = curr + 1 if s[i + 1] == c else 1
except IndexError:
pass
longest = max(curr, longest)
return longest
Solution bytecode
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
$ python -i solution.py
>>> import dis; dis.dis(solution)
66 0 LOAD_CONST 1 (1)
2 STORE_FAST 1 (curr)
67 4 LOAD_FAST 0 (s)
6 POP_JUMP_IF_TRUE 12
8 LOAD_CONST 2 (0)
10 JUMP_FORWARD 2 (to 14)
>> 12 LOAD_CONST 1 (1)
>> 14 STORE_FAST 2 (longest)
68 16 SETUP_LOOP 84 (to 102)
18 LOAD_GLOBAL 0 (enumerate)
20 LOAD_FAST 0 (s)
22 CALL_FUNCTION 1
24 GET_ITER
>> 26 FOR_ITER 72 (to 100)
28 UNPACK_SEQUENCE 2
30 STORE_FAST 3 (i)
32 STORE_FAST 4 (c)
69 34 SETUP_EXCEPT 32 (to 68)
70 36 LOAD_FAST 0 (s)
38 LOAD_FAST 3 (i)
40 LOAD_CONST 1 (1)
42 BINARY_ADD
44 BINARY_SUBSCR
46 LOAD_FAST 4 (c)
48 COMPARE_OP 2 (==)
50 POP_JUMP_IF_FALSE 60
52 LOAD_FAST 1 (curr)
54 LOAD_CONST 1 (1)
56 BINARY_ADD
58 JUMP_FORWARD 2 (to 62)
>> 60 LOAD_CONST 1 (1)
>> 62 STORE_FAST 1 (curr)
64 POP_BLOCK
66 JUMP_FORWARD 20 (to 88)
71 >> 68 DUP_TOP
70 LOAD_GLOBAL 1 (IndexError)
72 COMPARE_OP 10 (exception match)
74 POP_JUMP_IF_FALSE 86
76 POP_TOP
78 POP_TOP
80 POP_TOP
72 82 POP_EXCEPT
84 JUMP_FORWARD 2 (to 88)
>> 86 END_FINALLY
73 >> 88 LOAD_GLOBAL 2 (max)
90 LOAD_FAST 1 (curr)
92 LOAD_FAST 2 (longest)
94 CALL_FUNCTION 2
96 STORE_FAST 2 (longest)
98 JUMP_ABSOLUTE 26
>> 100 POP_BLOCK
75 >> 102 LOAD_FAST 2 (longest)
104 RETURN_VALUE
Tests
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import pytest
from hypothesis import given
from hypothesis import strategies as st
from random import sample
from solution import solution
class TestArgumentAndReturn:
"""Test passed argument and return value."""
@pytest.mark.xfail
def test_wrong_arg_type(self):
"""Should fail for unimplemented argument data type."""
assert (
solution(1) == 0
), "expected failure for unimplemented input validation"
def test_return_type(self):
"""Should return value of type integer."""
assert isinstance(solution(), int), "expected return type to be int"
class TestMeaninglessResults:
"""Test edge cases producing meaningless results."""
def test_no_input(self):
"""Should return 0 for no input."""
assert solution() == 0, "expected 0 for no input"
def test_empty_string_input(self):
"""Should return 0 for empty string."""
assert solution("") == 0, "expected 0 for empty string"
def test_single_char_input(self):
"""Should return 1 for one-character string."""
assert solution("a") == 1, "expected 1 for one-character string"
class TestSimpleMeaningfulResults:
"""Test simplest possible meaningful results."""
def test_simplest_meaningful_result(self):
"""Should return 1 for string with no repeated characters."""
assert solution("ab") == 1, "expected 1 for string 'ab'"
def test_shortest_long_string(self):
"""Should return 2 for a string repeating two characters."""
assert solution("aa") == 2, "expected 2 for string 'aa'"
class TestPositional:
"""Place the longest substring in different positions in the string."""
def test_longest_first(self):
"""Should return 3 for repetition of 3 at start of string."""
assert solution("aaab") == 3, "expected 3 for string 'aaab'"
def test_longest_last(self):
"""Should return 3 for repetition of 3 at end of string."""
assert solution("abbb") == 3, "expected 3 for string 'abbb'"
def test_longest_middle(self):
"""Should return 3 for repetition of 3 in middle of string."""
assert solution("aabbbc") == 3, "expected 3 for string 'aabbbc'"
class TestRandomlyGenerated:
"""Test with randomly generated strings."""
def test_randomly_generated_string(self):
"""Should correctly evaluate a randomly generated string."""
strs = [x * str(x) for x in sample(range(10), 5)]
longest = max([len(x) for x in strs])
strs_concat = "".join(strs)
assert longest == solution(
strs_concat
), f"expected {longest} for string '{strs_concat}'"
class TestProvidedTests:
"""Tests provided with problem."""
@pytest.mark.parametrize(
"test_input, expected",
[
("", 0),
("a", 1),
("aa", 2),
("aaba", 2),
("abababa", 1),
("abababaab", 2),
("sdsffffse", 4),
("ddvvrwwwrggg", 3),
],
)
def test_provided_tests(self, test_input, expected):
"""Should correctly evaluate provided test data."""
assert (
solution(test_input) == expected
), f"expected {expected} for string '{test_input}'"
@given(a=st.text("A"), b=st.text("B"))
def test_property_test_two_repeated_chars(a, b):
"""Should correctly evaluate automatically generated property test data."""
longest = max(len(a), len(b))
assert solution(a + b) == longest, f"expected {longest} for string {a + b}"
def _benchmark_setup():
"""Create benchmarking data."""
s = "A" + "B" * 1000
return (s,), {}
def _make_benchmark(solution):
"""Create a benchmarking function."""
def f(benchmark):
"""Benchmark the solution."""
result = benchmark.pedantic(solution, setup=_benchmark_setup)
assert result == 1000, "expected 1000 (benchmarking test)"
return f
test_benchmark_solution = _make_benchmark(solution)