def is_valid(s):
if not s:
return True
char = "x"
count = 0
for c in s:
if c != char:
char, count = c, 1
else:
count += 1
if count == 3:
return False
return True
# Code by apple apple
def inverse(c):
return 'b' if c == 'a' else 'a'
def solve(_s):
s = [char for char in _s]
# boundary conditions
if len(s) < 3:
for i, c in enumerate(s):
if c == '?':
s[i] = 'b'
return ''.join(s)
if s[0:2] == ["?", "?"]:
s[0] = 'a'
if s[0:2] == ["?", "a"] or s[0:2] == ["?", "b"]:
s[0] = inverse(s[1])
if s[0:3] == ['a', '?', '?'] or s[0:3] == ['b', '?', '?']:
s[1] = inverse(s[0])
if s[0:3] == ['a', '?', 'b'] or s[0:3] == ['b', '?', 'a']:
s[1] = s[0]
# primary loop
for i in range(1, len(s)):
if s[i] == '?':
if s[i-1] != (s[i+1] if i + 1 < len(s) else s[i-1]) and s[i-2] == (s[i+1] if (i + 1 < len(s) and i > 1) else s[i-2]):
s[i] = s[i-1] # ba?b => baab
else:
s[i] = inverse(s[i-1])
return ''.join(s)
# My greedy solution
def f(s):
if len(s) == 2:
return s.replace('?', 'a')
aa = ['a', 'a']
bb = ['b', 'b']
out = []
i = 0
a, b = 0, 0
while i < len(s):
if s[i] == 'a' or (s[i] == '?' and b == 2):
if s[i] == 'a' and a == 2:
if s[i-3:i-1] == "??":
out[i-3], out[i-2] = out[i-2], out[i-3]
a -= 1
else:
return ""
out.append('a')
a, b = a + 1, 0
i += 1
elif s[i] == 'b' or (s[i] == '?' and a == 2):
if s[i] == 'b' and b == 2:
if s[i-3:i-1] == "??":
out[i-3], out[i-2] = out[i-2], out[i-3]
b -= 1
else:
return ""
out.append('b')
a, b = 0, b + 1
i += 1
elif i == len(s) - 1:
out.append('a' if b else 'b')
i += 1
elif i == len(s) - 2:
if s[i+1] == '?':
out.extend(aa if b else bb)
else:
out.append('a' if b else 'b')
out.append(s[i+1])
i += 2
elif s[i+1] == '?':
if a:
out.append('a')
a, b = a + 1, 0
else:
out.append('b')
a, b = 0, b + 1
i += 1
elif s[i+1] == 'a':
if a or b < 2:
out.append('b')
a, b = 0, b + 1
else:
out.append('a')
a, b = a + 1, 0
i += 1
elif s[i+1] == 'b':
if b or a < 2:
out.append('a')
a, b = a + 1, 0
else:
out.append('b')
a, b = 0, b + 1
i += 1
return ''.join(out)
strs = [
"a?bb", # "aabb"
"??abb", # "ababb" or "bbabb" or "baabb"
"a?b?aa", # "aabbaa"
"?bb?",
#"aa?bb", # NO SOLUTION
"aa??aa", # "aabbaa"
"ab???bb?",
"????",
"??",
"?????",
"??????",
"?",
"a?",
"a??",
"a???",
"b?",
"b??",
"b???",
"a?a",
"a?b",
"b?a",
"b?b",
"a??a",
"a??b",
"b??a",
"b??b",
"aa?",
"ba?",
"a?bb",
"?bb?",
"??abb",
"a?b?aa",
"ab???bb?",
#"aa?bb"
]
for s in strs:
_solve = solve(s)
_f = f(s)
print("%s\n%s, %s, %s, %s\n" % (s, is_valid(_f), is_valid(_solve), _f, _solve))
import random
def get_random(n):
char = 'x'
count = 0
out = []
not_c = lambda c: 'a' if c == 'b' else 'b'
for _ in range(n):
c = ['a', 'b'][int(random.random() * 2)]
if c != char:
out.append(c)
char, count = c, 1
elif count == 2:
out.append(not_c(c))
char, count = not_c(c), 1
else:
out.append(c)
count += 1
for i in range(n):
if int(random.random() * 2):
out[i] = '?'
return ''.join(out)
num_tests = 1000
n = 20
print("Starting random tests...")
for _ in range(num_tests):
s = get_random(n)
_solve = solve(s)
_f = f(s)
valid_solve = is_valid(_solve)
valid_f = is_valid(_f)
if not valid_f or not valid_solve:
print(s, valid_f, valid_solve, _f, _solve)
break
print("Done testing")
ZGVmIGlzX3ZhbGlkKHMpOgogIGlmIG5vdCBzOgogICAgcmV0dXJuIFRydWUKICBjaGFyID0gIngiCiAgY291bnQgPSAwCiAgZm9yIGMgaW4gczoKICAgIGlmIGMgIT0gY2hhcjoKICAgICAgY2hhciwgY291bnQgPSBjLCAxCiAgICBlbHNlOgogICAgICBjb3VudCArPSAxCiAgICAgIGlmIGNvdW50ID09IDM6CiAgICAgICAgcmV0dXJuIEZhbHNlCiAgcmV0dXJuIFRydWUKCgojIENvZGUgYnkgYXBwbGUgYXBwbGUKZGVmIGludmVyc2UoYyk6CiAgcmV0dXJuICdiJyBpZiBjID09ICdhJyBlbHNlICdhJwoKZGVmIHNvbHZlKF9zKToKICAgcyA9IFtjaGFyIGZvciBjaGFyIGluIF9zXQoKICAgIyBib3VuZGFyeSBjb25kaXRpb25zCiAgIAogICBpZiBsZW4ocykgPCAzOgogICAgIGZvciBpLCBjIGluIGVudW1lcmF0ZShzKToKICAgICAgIGlmIGMgPT0gJz8nOgogICAgICAgICBzW2ldID0gJ2InCiAgICAgcmV0dXJuICcnLmpvaW4ocykKICAgCiAgIGlmIHNbMDoyXSA9PSBbIj8iLCAiPyJdOgogICAgIHNbMF0gPSAnYScKICAgaWYgc1swOjJdID09IFsiPyIsICJhIl0gb3Igc1swOjJdID09IFsiPyIsICJiIl06CiAgICAgc1swXSA9IGludmVyc2Uoc1sxXSkKICAgaWYgc1swOjNdID09IFsnYScsICc/JywgJz8nXSBvciBzWzA6M10gPT0gWydiJywgJz8nLCAnPyddOgogICAgIHNbMV0gPSBpbnZlcnNlKHNbMF0pCiAgIGlmIHNbMDozXSA9PSBbJ2EnLCAnPycsICdiJ10gb3Igc1swOjNdID09IFsnYicsICc/JywgJ2EnXToKICAgICBzWzFdID0gc1swXQogICAKICAgIyBwcmltYXJ5IGxvb3AKCiAgIGZvciBpIGluIHJhbmdlKDEsIGxlbihzKSk6CiAgICAgaWYgc1tpXSA9PSAnPyc6CiAgICAgICBpZiBzW2ktMV0gIT0gKHNbaSsxXSBpZiBpICsgMSA8IGxlbihzKSBlbHNlIHNbaS0xXSkgYW5kIHNbaS0yXSA9PSAoc1tpKzFdIGlmIChpICsgMSA8IGxlbihzKSBhbmQgaSA+IDEpIGVsc2Ugc1tpLTJdKToKICAgICAgICAgc1tpXSA9IHNbaS0xXSAjIGJhP2IgPT4gYmFhYgogICAgICAgZWxzZToKICAgICAgICAgc1tpXSA9IGludmVyc2Uoc1tpLTFdKQogICAgCiAgIHJldHVybiAnJy5qb2luKHMpCgoKIyBNeSBncmVlZHkgc29sdXRpb24KZGVmIGYocyk6CiAgaWYgbGVuKHMpID09IDI6CiAgICByZXR1cm4gcy5yZXBsYWNlKCc/JywgJ2EnKQogICAgCiAgYWEgPSBbJ2EnLCAnYSddCiAgYmIgPSBbJ2InLCAnYiddCgogIG91dCA9IFtdCiAgaSA9IDAKICBhLCBiID0gMCwgMAoKICB3aGlsZSBpIDwgbGVuKHMpOgogICAgaWYgc1tpXSA9PSAnYScgb3IgKHNbaV0gPT0gJz8nIGFuZCBiID09IDIpOgogICAgICBpZiBzW2ldID09ICdhJyBhbmQgYSA9PSAyOgogICAgICAgIGlmIHNbaS0zOmktMV0gPT0gIj8/IjoKICAgICAgICAgIG91dFtpLTNdLCBvdXRbaS0yXSA9IG91dFtpLTJdLCBvdXRbaS0zXQogICAgICAgICAgYSAtPSAxCiAgICAgICAgZWxzZToKICAgICAgICAgIHJldHVybiAiIgogICAgICBvdXQuYXBwZW5kKCdhJykKICAgICAgYSwgYiA9IGEgKyAxLCAwCiAgICAgIGkgKz0gMQogICAgZWxpZiBzW2ldID09ICdiJyBvciAoc1tpXSA9PSAnPycgYW5kIGEgPT0gMik6CiAgICAgIGlmIHNbaV0gPT0gJ2InIGFuZCBiID09IDI6CiAgICAgICAgaWYgc1tpLTM6aS0xXSA9PSAiPz8iOgogICAgICAgICAgb3V0W2ktM10sIG91dFtpLTJdID0gb3V0W2ktMl0sIG91dFtpLTNdCiAgICAgICAgICBiIC09IDEKICAgICAgICBlbHNlOgogICAgICAgICAgcmV0dXJuICIiCiAgICAgIG91dC5hcHBlbmQoJ2InKQogICAgICBhLCBiID0gMCwgYiArIDEKICAgICAgaSArPSAxCiAgICBlbGlmIGkgPT0gbGVuKHMpIC0gMToKICAgICAgb3V0LmFwcGVuZCgnYScgaWYgYiBlbHNlICdiJykKICAgICAgaSArPSAxCiAgICBlbGlmIGkgPT0gbGVuKHMpIC0gMjoKICAgICAgaWYgc1tpKzFdID09ICc/JzoKICAgICAgICBvdXQuZXh0ZW5kKGFhIGlmIGIgZWxzZSBiYikKICAgICAgZWxzZToKICAgICAgICBvdXQuYXBwZW5kKCdhJyBpZiBiIGVsc2UgJ2InKQogICAgICAgIG91dC5hcHBlbmQoc1tpKzFdKQogICAgICBpICs9IDIKICAgIGVsaWYgc1tpKzFdID09ICc/JzoKICAgICAgaWYgYToKICAgICAgICBvdXQuYXBwZW5kKCdhJykKICAgICAgICBhLCBiID0gYSArIDEsIDAKICAgICAgZWxzZToKICAgICAgICBvdXQuYXBwZW5kKCdiJykKICAgICAgICBhLCBiID0gMCwgYiArIDEKICAgICAgaSArPSAxCiAgICBlbGlmIHNbaSsxXSA9PSAnYSc6CiAgICAgIGlmIGEgb3IgYiA8IDI6CiAgICAgICAgb3V0LmFwcGVuZCgnYicpCiAgICAgICAgYSwgYiA9IDAsIGIgKyAxCiAgICAgIGVsc2U6CiAgICAgICAgb3V0LmFwcGVuZCgnYScpCiAgICAgICAgYSwgYiA9IGEgKyAxLCAwCiAgICAgIGkgKz0gMQogICAgZWxpZiBzW2krMV0gPT0gJ2InOgogICAgICBpZiBiIG9yIGEgPCAyOgogICAgICAgIG91dC5hcHBlbmQoJ2EnKQogICAgICAgIGEsIGIgPSBhICsgMSwgMAogICAgICBlbHNlOgogICAgICAgIG91dC5hcHBlbmQoJ2InKQogICAgICAgIGEsIGIgPSAwLCBiICsgMQogICAgICBpICs9IDEKCiAgcmV0dXJuICcnLmpvaW4ob3V0KQoKCnN0cnMgPSBbCiAgImE/YmIiLCAjICJhYWJiIgogICI/P2FiYiIsICMgImFiYWJiIiBvciAiYmJhYmIiIG9yICJiYWFiYiIKICAiYT9iP2FhIiwgIyAiYWFiYmFhIgogICI/YmI/IiwKICAjImFhP2JiIiwgIyBOTyBTT0xVVElPTgogICJhYT8/YWEiLCAjICJhYWJiYWEiCiAgImFiPz8/YmI/IiwKICAiPz8/PyIsCiAgIj8/IiwKICAiPz8/Pz8iLAogICI/Pz8/Pz8iLAogICI/IiwKICAiYT8iLAogICJhPz8iLAogICJhPz8/IiwKICAiYj8iLAogICJiPz8iLAogICJiPz8/IiwKICAiYT9hIiwKICAiYT9iIiwKICAiYj9hIiwKICAiYj9iIiwKICAiYT8/YSIsCiAgImE/P2IiLAogICJiPz9hIiwKICAiYj8/YiIsCiAgImFhPyIsCiAgImJhPyIsCiAgImE/YmIiLAogICI/YmI/IiwKICAiPz9hYmIiLAogICJhP2I/YWEiLAogICJhYj8/P2JiPyIsCiAgIyJhYT9iYiIKXQoKCmZvciBzIGluIHN0cnM6CiAgX3NvbHZlID0gc29sdmUocykKICBfZiA9IGYocykKICBwcmludCgiJXNcbiVzLCAlcywgJXMsICVzXG4iICUgKHMsIGlzX3ZhbGlkKF9mKSwgaXNfdmFsaWQoX3NvbHZlKSwgX2YsIF9zb2x2ZSkpCgoKaW1wb3J0IHJhbmRvbQoKZGVmIGdldF9yYW5kb20obik6CiAgY2hhciA9ICd4JwogIGNvdW50ID0gMAogIG91dCA9IFtdCiAgbm90X2MgPSBsYW1iZGEgYzogJ2EnIGlmIGMgPT0gJ2InIGVsc2UgJ2InCgogIGZvciBfIGluIHJhbmdlKG4pOgogICAgYyA9IFsnYScsICdiJ11baW50KHJhbmRvbS5yYW5kb20oKSAqIDIpXQogICAgaWYgYyAhPSBjaGFyOgogICAgICBvdXQuYXBwZW5kKGMpCiAgICAgIGNoYXIsIGNvdW50ID0gYywgMQogICAgZWxpZiBjb3VudCA9PSAyOgogICAgICBvdXQuYXBwZW5kKG5vdF9jKGMpKQogICAgICBjaGFyLCBjb3VudCA9IG5vdF9jKGMpLCAxCiAgICBlbHNlOgogICAgICBvdXQuYXBwZW5kKGMpCiAgICAgIGNvdW50ICs9IDEKCiAgZm9yIGkgaW4gcmFuZ2Uobik6CiAgICAgaWYgaW50KHJhbmRvbS5yYW5kb20oKSAqIDIpOgogICAgICBvdXRbaV0gPSAnPycKCiAgcmV0dXJuICcnLmpvaW4ob3V0KQoKbnVtX3Rlc3RzID0gMTAwMApuID0gMjAKCnByaW50KCJTdGFydGluZyByYW5kb20gdGVzdHMuLi4iKQoKZm9yIF8gaW4gcmFuZ2UobnVtX3Rlc3RzKToKICBzID0gZ2V0X3JhbmRvbShuKQogIF9zb2x2ZSA9IHNvbHZlKHMpCiAgX2YgPSBmKHMpCiAgdmFsaWRfc29sdmUgPSBpc192YWxpZChfc29sdmUpCiAgdmFsaWRfZiA9IGlzX3ZhbGlkKF9mKQogIGlmIG5vdCB2YWxpZF9mIG9yIG5vdCB2YWxpZF9zb2x2ZToKICAgIHByaW50KHMsIHZhbGlkX2YsIHZhbGlkX3NvbHZlLCBfZiwgX3NvbHZlKQogICAgYnJlYWsKCnByaW50KCJEb25lIHRlc3RpbmciKQ==
a?bb
True, True, aabb, aabb
??abb
True, True, bbabb, ababb
a?b?aa
True, True, aabbaa, aabbaa
?bb?
True, True, abba, abba
aa??aa
True, True, aabbaa, aabbaa
ab???bb?
True, True, abbaabba, abababba
????
True, True, bbab, abab
??
True, True, aa, bb
?????
True, True, bbabb, ababa
??????
True, True, bbaaba, ababab
?
True, True, b, b
a?
True, True, aa, ab
a??
True, True, abb, aba
a???
True, True, aaba, abab
b?
True, True, ba, bb
b??
True, True, baa, bab
b???
True, True, bbab, baba
a?a
True, True, aba, aba
a?b
True, True, abb, aab
b?a
True, True, baa, bba
b?b
True, True, bab, bab
a??a
True, True, aaba, abba
a??b
True, True, aabb, abab
b??a
True, True, bbaa, baba
b??b
True, True, bbab, baab
aa?
True, True, aab, aab
ba?
True, True, bab, bab
a?bb
True, True, aabb, aabb
?bb?
True, True, abba, abba
??abb
True, True, bbabb, ababb
a?b?aa
True, True, aabbaa, aabbaa
ab???bb?
True, True, abbaabba, abababba
Starting random tests...
Done testing