यह थिज़र के वर्तमान में अपूर्ण छद्मकोश की तर्ज पर है। विचार शेष आइटम प्रकारों में से सबसे अधिक बार लेने के लिए है जब तक कि इसे अभी नहीं लिया गया। ( इस एल्गोरिथम के कोएडी के कार्यान्वयन को भी देखें ।)
import collections
import heapq
class Sentinel:
pass
def david_eisenstat(lst):
counts = collections.Counter(lst)
heap = [(-count, key) for key, count in counts.items()]
heapq.heapify(heap)
output = []
last = Sentinel()
while heap:
minuscount1, key1 = heapq.heappop(heap)
if key1 != last or not heap:
last = key1
minuscount1 += 1
else:
minuscount2, key2 = heapq.heappop(heap)
last = key2
minuscount2 += 1
if minuscount2 != 0:
heapq.heappush(heap, (minuscount2, key2))
output.append(last)
if minuscount1 != 0:
heapq.heappush(heap, (minuscount1, key1))
return output
शुद्धता का प्रमाण
दो आइटम प्रकारों के लिए, k1 और k2 के साथ, इष्टतम समाधान में k2 - k1 - 1 दोष है यदि k1 <k2, 0 दोष यदि k1 = k2, और k1 - k2 - 1 दोष है तो b1 / k2। = मामला स्पष्ट है। दूसरे सममित हैं; अल्पसंख्यक तत्व का प्रत्येक उदाहरण कुल संभव k1 + k2 - 1 के अधिकांश दो दोषों को रोकता है।
यह लालची एल्गोरिथम इष्टतम समाधान लौटाता है, निम्न तर्क द्वारा। हम एक उपसर्ग (आंशिक समाधान) को सुरक्षित कहते हैं यदि यह एक इष्टतम समाधान तक विस्तारित होता है। स्पष्ट रूप से खाली उपसर्ग सुरक्षित है, और यदि एक सुरक्षित उपसर्ग एक संपूर्ण समाधान है तो वह समाधान इष्टतम है। यह व्यावहारिक रूप से यह दिखाने के लिए पर्याप्त है कि प्रत्येक लालची कदम सुरक्षा बनाए रखता है।
एक लालची कदम एक दोष का परिचय देता है कि केवल एक ही वस्तु प्रकार रहता है, जिस स्थिति में जारी रखने का केवल एक ही तरीका है, और वह तरीका सुरक्षित है। अन्यथा, P को विचाराधीन कदम से ठीक पहले P (सुरक्षित) उपसर्ग होने दें, P 'को उपसर्ग के ठीक बाद होने दें, और S को P का विस्तार करने वाला एक इष्टतम समाधान होने दें। यदि S, P का विस्तार करता है, तो हम कर रहे हैं। अन्यथा, P '= Px और S = PQ और Q = yQ' दें, जहाँ x और y आइटम हैं और Q और Q 'क्रम हैं।
मान लीजिए कि पहले P, y के साथ समाप्त नहीं होता है। एल्गोरिथ्म की पसंद से, x कम से कम क्यू में लगातार वाई के रूप में है। केवल x और y वाले Q के अधिकतम सबस्ट्रिंग पर विचार करें। यदि पहले सबरिंग में कम से कम कई x की y के रूप में है, तो इसे x के साथ शुरू करने के लिए अतिरिक्त दोषों को प्रस्तुत किए बिना फिर से लिखा जा सकता है। यदि पहली सबस्ट्रिंग में x की तुलना में अधिक y है, तो कुछ अन्य सबस्ट्रिंग में y की तुलना में अधिक x है, और हम अतिरिक्त दोषों के बिना इन सबस्ट्रिंग्स को फिर से लिख सकते हैं ताकि x पहले चला जाए। दोनों ही मामलों में, हमें एक इष्टतम समाधान T मिलता है, जो कि आवश्यकतानुसार P 'का विस्तार करता है।
मान लीजिए कि अब P, y के साथ समाप्त होता है। X की पहली घटना को सामने की ओर ले जाकर Q को संशोधित करें। ऐसा करने में, हम अधिकांश एक दोष (जहां x हुआ करते थे) और एक दोष (yy) को समाप्त करते हैं।
सभी समाधान उत्पन्न करना
यह पता लगाने के लिए कि वर्तमान में विचाराधीन किसी तरह से विश्व स्तर पर विवश है, यह पता लगाने के लिए टोबियास_क का उत्तर प्लस कुशल परीक्षण है। स्पर्शोन्मुख चलने का समय इष्टतम है, क्योंकि उत्पादन की लंबाई के क्रम में पीढ़ी का ओवरहेड होता है। दुर्भाग्य से सबसे खराब मामला द्विघात है; इसे बेहतर डेटा संरचनाओं के साथ रैखिक (इष्टतम) तक कम किया जा सकता है।
from collections import Counter
from itertools import permutations
from operator import itemgetter
from random import randrange
def get_mode(count):
return max(count.items(), key=itemgetter(1))[0]
def enum2(prefix, x, count, total, mode):
prefix.append(x)
count_x = count[x]
if count_x == 1:
del count[x]
else:
count[x] = count_x - 1
yield from enum1(prefix, count, total - 1, mode)
count[x] = count_x
del prefix[-1]
def enum1(prefix, count, total, mode):
if total == 0:
yield tuple(prefix)
return
if count[mode] * 2 - 1 >= total and [mode] != prefix[-1:]:
yield from enum2(prefix, mode, count, total, mode)
else:
defect_okay = not prefix or count[prefix[-1]] * 2 > total
mode = get_mode(count)
for x in list(count.keys()):
if defect_okay or [x] != prefix[-1:]:
yield from enum2(prefix, x, count, total, mode)
def enum(seq):
count = Counter(seq)
if count:
yield from enum1([], count, sum(count.values()), get_mode(count))
else:
yield ()
def defects(lst):
return sum(lst[i - 1] == lst[i] for i in range(1, len(lst)))
def test(lst):
perms = set(permutations(lst))
opt = min(map(defects, perms))
slow = {perm for perm in perms if defects(perm) == opt}
fast = set(enum(lst))
print(lst, fast, slow)
assert slow == fast
for r in range(10000):
test([randrange(3) for i in range(randrange(6))])
[1, 2, 1, 3, 1, 4, 1, 5]
जैसा[1, 3, 1, 2, 1, 4, 1, 5]
आपकी कसौटी है वैसा ही कुछ है ?