można rozwiązać ten z programowania dynamicznego. Przechowywać mapę wszystkich możliwych sum częściowych (mapowanie z minimalną ilością zmian do osiągnięcia tej kwoty), a następnie zaktualizować jeden numer na raz,
Oto zwięzły rozwiązanie Python:
def signs(nums):
xs = {nums[0]: 0}
for num in nums[1:]:
ys = dict()
for d, k in xs.iteritems():
for cost, n in enumerate([num, -num]):
ys[d+n] = min(ys.get(d+n, 1e100), k+cost)
xs = ys
return xs.get(0, -1)
print signs([1, 1, -4, -4, -4, -2, -2])
W teoria ta ma wykładniczą złożoność w najgorszym przypadku (ponieważ liczba częściowych sum może się podwoić na każdym kroku). Jeśli jednak (jak tutaj) podane liczby są zawsze (ograniczone) małymi intami, to liczba sum cząstkowych rośnie liniowo, a program działa w czasie O (n^2).
Nieco bardziej zoptymalizowana wersja wykorzystuje posortowaną tablicę (suma częściowa, koszt) zamiast dyktowania. Można odrzucić częściowe kwoty, które są zbyt duże lub zbyt małe (co uniemożliwia osiągnięcie wartości 0, przy założeniu, że wszystkie pozostałe elementy mieszczą się w zakresie od -300 do +300). Działa to mniej więcej dwa razy szybciej i jest bardziej naturalną implementacją, która umożliwia przeniesienie do języka niższego poziomu niż Python dla maksymalnej prędkości.
def merge(xs, num):
i = j = 0
ci = 0 if num >= 0 else 1
cj = 0 if num < 0 else 1
num = abs(num)
while j < len(xs):
if xs[i][0] + num < xs[j][0] - num:
yield (xs[i][0] + num, xs[i][1] + ci)
i += 1
elif xs[i][0] + num > xs[j][0] - num:
yield (xs[j][0] - num, xs[j][1] + cj)
j += 1
else:
yield (xs[i][0] + num, min(xs[i][1] + ci, xs[j][1] + cj))
i += 1
j += 1
while i < len(xs):
yield (xs[i][0] + num, xs[i][1] + ci)
i += 1
def signs2(nums):
xs = [(nums[0], 0)]
for i in xrange(1, len(nums)):
limit = (len(nums) - 1 - i) * 300
xs = [x for x in merge(xs, nums[i]) if -limit <= x[0] <= limit]
for x, c in xs:
if x == 0: return c
return -1
print signs2([1, 1, -4, -4, -4, -2, -2])
Jednym ze sposobów, aby przycinać drzewa przeszukiwania w przypadku wycofywania może być uświadomienie sobie, że '+ 4 - 4' jest taka sama jak' - 4 + 4'. –
Złap łączną parzystość, jeśli jest to druk nieparzysty -1. – Vesper
Nie, cyfry to "1 <= x <300' – user2660964