Я вызвал ваше решение с выражением 0*0+1*1
, получил ответ 0. А правильный ответ 3 для выражения 0*0
. Ошибка в алгоритме.
NB Это вторая попытка. Первая строилась на анализе выражений "сверху вниз" и ломалась на 10+1
и 10*1
. Если обработку 10+1
можно было починить, глядя на предыдущее слагаемое, то 10*1
куда хуже. Оно не чинится, если мы разбили выражение на слагаемые и коэффициенты. Я бросил этот подход и сделал по другому.
Класс Expr
принимает последовательные символы (e.update(с)
) и содержит следующие поля:
e.length
– длина текста, пока он синтаксически правильный;
e.valid_prefix
– истина, если текст может быть продолжен до правильной формулы с нулевым значением;
e.valid_zero
– истина, если текст прямо сейчас представляет правильную формулу с нулевым значением;
e.last_term_is_zero
– истина, если последнее слагаемое в формуле содержит нулевой множитель.
На каждой итерации хранятся максимум три выражения-корректных префикса:
- самая длинная формула, у которой последний множитель не ноль (но которая имеет шанс стать нулевой в будущем);
- самая длинная формула, у которой последний множитель ноль (она обновляет текущий максимум);
- формула из одного последнего символа.
Алгоритм работает за линейное время и избегает, как мне кажется, описания большого количества тонких мест.
Я переделал программу, чтобы её можно было тестировать с разными текстами. Для исходного текста её надо запускать так: cat 24_17641.txt | python zero-expr.py
.
class Expr:
def __init__(self):
self.length = 0
self.valid_prefix = True
self.valid_zero = False
self.last_term_is_zero = False
self._last_factor = '' # '' for empty last factor
# '0' for zero last factor
# '1' for nonzero last factor
def update(self, char):
if self.valid_prefix and self._update(char):
self.length += 1
self.valid_zero = self.last_term_is_zero and self._last_factor != ''
else:
self.valid_prefix = False
self.valid_zero = False
def _update(self, char):
if char == '+':
if self._last_factor == '':
return False # no digit before `+` sign
if not self.last_term_is_zero:
return False # whole expression is above zero
self.last_term_is_zero = False
self._last_factor = '' # start new factor
return True
if char == '*':
if self._last_factor == '':
return False # no digit before `*` sign
self._last_factor = '' # start new factor
return True
if char == '0':
if self._last_factor == '':
self._last_factor = '0'
self.last_term_is_zero = True
return True
return self._last_factor != '0' # leading zero before digit
if '1' <= char <= '9':
if self._last_factor == '':
self._last_factor = '1' # nonzero last factor
return True
return self._last_factor != '0' # leading zero before digit
return False # unknown character
def main():
with open(0) as f:
text = f.read()
max_length = 0
exprs = []
for c in text:
exprs.append(Expr())
for e in exprs:
e.update(c)
if e.valid_prefix and e.valid_zero:
max_length = max(max_length, e.length)
new_exprs = []
for e in exprs:
if e.valid_prefix:
new_exprs.append(e)
break
for e in exprs:
if e.valid_prefix and e.last_term_is_zero and e not in new_exprs:
new_exprs.append(e)
break
exprs = new_exprs
print(max_length)
main()