সংলগ্ন সমান উপাদান ছাড়াই তালিকার সমস্ত ক্রমবিন্যাস তৈরি করুন


87

যখন আমরা একটি তালিকা বাছাই, পছন্দ

a = [1,2,3,3,2,2,1]
sorted(a) => [1, 1, 2, 2, 2, 3, 3]

সমতুল্য উপাদানগুলি সর্বদা ফলাফলের তালিকায় সংলগ্ন থাকে।

আমি কীভাবে বিপরীত কাজটি অর্জন করতে পারি - তালিকাটি এলোমেলো করে তুলি যাতে সমান উপাদানগুলি কখনই (বা যত কম সম্ভব) সংলগ্ন হয় না?

উদাহরণস্বরূপ, উপরের তালিকার জন্য সম্ভাব্য সমাধানগুলির মধ্যে একটি

p = [1,3,2,3,2,1,2]

আরও আনুষ্ঠানিকভাবে, একটি তালিকা দেওয়া হয়েছে a, pএটির একটি অনুচ্ছেদ তৈরি করুন যা জোড়ের সংখ্যা হ্রাস করে p[i]==p[i+1]

যেহেতু তালিকাগুলি বড়, তাই সমস্ত ক্রম উত্পাদন এবং ফিল্টারিং কোনও বিকল্প নয়।

বোনাস প্রশ্ন: কীভাবে দক্ষতার সাথে এই জাতীয় অনুমতি দেওয়া যায়?

সমাধানগুলি পরীক্ষা করতে আমি এই কোডটি ব্যবহার করছি: https://gist.github.com/gebrkn/9f550094b3d24a35aebd

ইউপিডি: এখানে বিজয়ী নির্বাচন করা একটি কঠিন পছন্দ ছিল, কারণ অনেক লোক দুর্দান্ত উত্তর পোস্ট করেছিল। @VincentvanderWeele , @David Eisenstat , @Coady , @ enrico.bacis এবং @srgerg প্রদান ফাংশন যে সম্ভাব্য সর্বোত্তম বিন্যাস flawlessly উৎপন্ন। @ টোবিয়াস_ কে এবং ডেভিডও বোনাস প্রশ্নের উত্তর দিয়েছেন (সমস্ত অনুমান উত্পন্ন করে)। নির্ভুলতার প্রমাণের জন্য ডেভিডকে অতিরিক্ত পয়েন্ট।

@ ভিনসেন্টভান্ডারওয়েল থেকে কোডটি দ্রুততম বলে মনে হচ্ছে।


4
সুতরাং আপনি কি সাম্যের জন্য যত্ন ? এর মতো [1, 2, 1, 3, 1, 4, 1, 5]কিছু ঠিক [1, 3, 1, 2, 1, 4, 1, 5]আপনার মানদণ্ডের মতোই ?
বাকুরিউ

4
কোনও "দক্ষ" অ্যালগরিদম থাকতে পারে না। মত একটি তালিকা নিন [1, 1, 1, ..., 2, 3, 4, ..., N]সঙ্গে 2Nউপাদান। একটি ভাল ক্রমবর্ধমানতা পেতে আপনি টানা n > 1প্রতিটি জোড়ের মধ্যে একটি সংখ্যা রাখতে পারেন 1। তারপরে আপনি N/2উপাদানগুলিকে অনুমতি দিন এবং সমস্ত বৈধ ক্রমানুসরণ গ্রহণ করুন (যার অর্থ কোনওটি খারাপ নয়, তবে আরও কিছু থাকতে পারে)। এই জাতীয় আদেশের সংখ্যা হ'ল (এন ^ 2), সুতরাং আপনি ও (এন ^ 2) এর চেয়ে ভাল করতে পারবেন না। তবুও নিখুঁত পদ্ধতির চেয়ে ও (এন ^ 3) এর চেয়ে ভাল।
বাকুরিউ

6
@ বাকুরিউ: দুটি জিনিস: (১) স্পষ্ট হওয়া, আপনার উদাহরণটি দেখায় যে বোনাস প্রশ্নের জন্য কোনও কার্যকর অ্যালগরিদম থাকতে পারে না । (২) আপনার উদাহরণের সমস্ত অনুকূল সমাধান গণনা করা হচ্ছে ও ((এন / ২)!), যা ও (এন ^ 2) এর চেয়েও খারাপ (যেমন আপনার উদাহরণটি আপনি বুঝতে পেরেছিলেন তার চেয়ে অনেক শক্তিশালী :-)
j_random_hacker

11
@ এমএসডব্লিউ: আমি একটি ওয়েবসাইট তৈরি করছি এবং বিভিন্ন সরবরাহকারীর বিজ্ঞাপন ব্লকগুলির একটি সারি রয়েছে। আমি তাদের ব্যবস্থা করতে চাই যাতে একই সরবরাহকারীর কোনও ব্লক পাশাপাশি না থাকে।
জর্জি

4
আমি এটি বলব না যে এটি "ডুপ্লিকেটের কাছাকাছিও নয়", তবে অভিযুক্ত নকলটি একটি আলাদা প্রশ্ন, কারণ অভিন্ন উপাদানগুলির মধ্যে দূরত্ব বিবেচনা করা হয়। লোকেরা কেন ক্রাইর মন্তব্যের পরে বন্ধ করতে ভোট দিয়েছে: ভবিষ্যতে দয়া করে আরও মনোযোগ দিন।
ডেভিড আইজেনস্ট্যাট

উত্তর:


30

এটি থাইজারের বর্তমানে অসম্পূর্ণ সিউডোকোডের লাইন বরাবর রয়েছে। এই ধারণাটি হ'ল কেবলমাত্র নেওয়া না হলে বাকী আইটেম ধরণের সর্বাধিক ঘন ঘন গ্রহণ করা। ( এই অ্যালগরিদমের কোডির বাস্তবায়নও দেখুন ))

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

সঠিকতার প্রমাণ

দুটি আইটেমের জন্য, কে 1 এবং কে 2 গণনা করে, সর্বোত্তম সমাধানে কে 2 <কে 2 - 1 ত্রুটি থাকে, কে 1 = কে 2 হলে 0 ত্রুটি, এবং কে 1 - কে 2 - 1 ত্রুটি কে 1> কে 2 থাকে। = কেসটি সুস্পষ্ট। অন্যরা প্রতিসম হয়; সংখ্যালঘু উপাদানের প্রতিটি উদাহরণ সম্পূর্ণ কে 1 + কে 2 - 1 এর মধ্যে সর্বোচ্চ দুটি ত্রুটি প্রতিরোধ করে।

এই লোভী অ্যালগরিদম নিম্নলিখিত যুক্তি দ্বারা অনুকূল সমাধানগুলি প্রদান করে। আমরা একটি উপসর্গ (আংশিক সমাধান) নিরাপদ কল যদি এটি একটি অনুকূল সমাধান প্রসারিত। স্পষ্টতই খালি উপসর্গটি নিরাপদ এবং যদি কোনও নিরাপদ উপসর্গ সম্পূর্ণ সমাধান হয় তবে সমাধানটি সর্বোত্তম। প্রতিটি লোভী পদক্ষেপ সুরক্ষা বজায় রাখে তা প্ররোচিতভাবে দেখানোর পক্ষে যথেষ্ট।

লোভী পদক্ষেপটি একটি ত্রুটি পরিচয় করিয়ে দেওয়ার একমাত্র উপায় হ'ল যদি কেবলমাত্র একটি আইটেম ধরণের থাকে, সেক্ষেত্রে চালিয়ে যাওয়ার একমাত্র উপায় থাকে এবং সেই পথটি নিরাপদ। অন্যথায়, বিবেচনাধীন পদক্ষেপের ঠিক আগে পি-কে (নিরাপদ) উপসর্গ হিসাবে ধরা দিন, পি'র ঠিক পরের উপসর্গ হওয়া যাক এবং এসকে পি প্রসারিত করার একটি সর্বোত্তম সমাধান হতে দিন। যদি এস পি'কেও প্রসারিত করে, তবে আমরা সম্পন্ন করেছি। অন্যথায়, P '= Px এবং S = PQ এবং Q = yQ' দিন, যেখানে x এবং y আইটেম এবং Q এবং Q 'সিকোয়েন্স।

ধরা যাক প্রথমে পি এর y দিয়ে শেষ হবে না। অ্যালগরিদমের পছন্দ অনুসারে, x কমপক্ষে y হিসাবে ঘন ঘন হিসাবে y হয়। কেবলমাত্র x এবং y যুক্ত Q এর সর্বাধিক সাবস্ট্রিংগুলি বিবেচনা করুন। যদি প্রথম সাবস্ট্রিংয়ের কমপক্ষে Y এর মতো কম বেশি x থাকে তবে এক্স দিয়ে শুরু করার জন্য অতিরিক্ত ত্রুটিগুলি না পরিচয় দিয়ে এটি আবার লেখা যেতে পারে। প্রথম স্ট্রিংটিতে যদি x এর চেয়ে বেশি y থাকে তবে অন্য কিছু স্ট্রিংয়ের y এর চেয়ে আরও বেশি x থাকে এবং আমরা অতিরিক্ত ত্রুটি ছাড়াই এই সাবস্ট্রিংগুলিকে আবার লিখতে পারি যাতে এক্স প্রথমে যায়। উভয় ক্ষেত্রেই আমরা একটি অনুকূল সমাধান টি খুঁজে পাই যা প্রয়োজন অনুযায়ী পি 'প্রসারিত করে।

এখন ধরুন যে পি এর শেষ হবে y দিয়ে। এক্স এর প্রথম উপস্থিতিটি সামনের দিকে নিয়ে গিয়ে কিউ সংশোধন করুন। এটি করার মাধ্যমে, আমরা সর্বাধিক একটি ত্রুটি (যেখানে এক্স ব্যবহৃত হত) উপস্থাপন করি এবং একটি ত্রুটি (ইয়ি) নির্মূল করি।

সমস্ত সমাধান তৈরি করা হচ্ছে

বর্তমানে বিবেচনাধীন পছন্দটি কোনওভাবে বিশ্বব্যাপী সীমাবদ্ধ রয়েছে তা সনাক্ত করার জন্য এটি টোবিয়াস_কে এর উত্তর এবং দক্ষ পরীক্ষা। অ্যাসিম্পটোটিক চলমান সময়টি সর্বোত্তম, যেহেতু প্রজন্মের ওভারহেড আউটপুট দৈর্ঘ্যের ক্রম হয়। দুর্ভাগ্যক্রমে সবচেয়ে খারাপ ক্ষেত্রে বিলম্ব চতুর্ভুজযুক্ত; এটি আরও ভাল ডেটা স্ট্রাকচার সহ রৈখিক (অনুকূল) কমে যেতে পারে।

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))])

23

সুডোকোড:

  1. তালিকাটি বাছাই করুন
  2. বাছাই করা তালিকার প্রথম অর্ধেকের উপরে লুপ করুন এবং ফলাফল তালিকার সমস্ত সূচকগুলি পূরণ করুন
  3. বাছাই করা তালিকার দ্বিতীয়ার্ধের উপরে লুপ করুন এবং ফলাফল তালিকার সমস্ত বিজোড় সূচকগুলি পূরণ করুন

আপনার যদি কেবলমাত্র p[i]==p[i+1]ইনপুটটির অর্ধেকেরও বেশি একই উপাদান নিয়ে থাকে তবে এক্ষেত্রে একই উপাদানটিকে টানা দাগে লাগানো ছাড়া (পিজোন গর্তের নীতি অনুসারে) আর কোনও উপায় নেই।


মন্তব্যে উল্লেখ করা হয়েছে যে, এই উপাদানটির মধ্যে একটির মধ্যে অনেকগুলি দ্বন্দ্ব থাকতে পারে যদি কোনও উপাদান অন্ততপক্ষে ঘটে থাকে তবে n/2(বা n/2+1বিজোড়ের জন্য n; এটি সমান (n+1)/2)এবং বিজোড় উভয়ের জন্যই জেনারেলাইজড হয় )। সর্বাধিক দুটি এর মতো উপাদান রয়েছে এবং যদি দুটি থাকে তবে অ্যালগরিদম ঠিক কাজ করে। একমাত্র সমস্যাযুক্ত কেসটি যখন এমন একটি উপাদান থাকে যা অন্তত অর্ধেক সময় ঘটে থাকে। উপাদানটি সন্ধান করে এবং প্রথমে এটি মোকাবেলা করে আমরা কেবল এই সমস্যাটি সমাধান করতে পারি।

এটিকে সঠিকভাবে লেখার জন্য অজগর সম্পর্কে আমি যথেষ্ট পরিমাণে জানি না, সুতরাং আমি গিথুব থেকে পূর্ববর্তী সংস্করণটির ওপি'র প্রয়োগটি অনুলিপি করার জন্য স্বাধীনতা নিয়েছিলাম:

# Sort the list
a = sorted(lst)

# Put the element occurring more than half of the times in front (if needed)
n = len(a)
m = (n + 1) // 2
for i in range(n - m + 1):
    if a[i] == a[i + m - 1]:
        a = a[i:] + a[:i]
        break

result = [None] * n

# Loop over the first half of the sorted list and fill all even indices of the result list
for i, elt in enumerate(a[:m]):
    result[2*i] = elt

# Loop over the second half of the sorted list and fill all odd indices of the result list
for i, elt in enumerate(a[m:]):
    result[2*i+1] = elt

return result

আমার বোধগম্যতা থেকে, @ জোজো এটি করে - সর্বদা অনুকূল নয়।
জর্জি

10
আপনি 0-ভিত্তিক বা 1-ভিত্তিক সূচকগুলি ব্যবহার করেন কিনা তার উপর নির্ভর করে এটির জন্য [0, 1, 1]বা ব্যর্থ [0, 0, 1]
ফ্লর্নকোয়

@ জর্জি সত্যই আমার উত্তর হিসাবে এটি একই পদ্ধতি। (দ্রষ্টব্য যে হিউস্টার আমার আগে উত্তর দিয়েছেন!)। আমার কোডে তবে পদক্ষেপগুলি 2 এবং 3 একত্রিত হয়েছে, এইভাবে দক্ষতাটি অনুকূল করা।
জোজো

4
ভাল! এটি ভাল-পুরানো অফ-ওয়ান ত্রুটিটি আমার ভয়। সুতরাং, এই পদ্ধতিরটি সর্বোত্তম নয়, কারণ এতে 1 টির অনেক বেশি বিরোধ থাকতে পারে।
ভিনসেন্ট ভ্যান ডের ওয়েইল

4
@ হিস্টার: সমস্ত লাইট সবুজ! "0 ত্রুটি"।
জর্জি

10

পূর্ববর্তী আইটেমটি নয় এমন সর্বাধিক সাধারণ আইটেমটি বামে গ্রহণের জন্য ইতিমধ্যে দেওয়া অ্যালগরিদমটি সঠিক। এখানে একটি সাধারণ বাস্তবায়ন, যা সর্বাধিক সাধারণ ট্র্যাক করতে সর্বোত্তমভাবে একটি গাদা ব্যবহার করে।

import collections, heapq
def nonadjacent(keys):
    heap = [(-count, key) for key, count in collections.Counter(a).items()]
    heapq.heapify(heap)
    count, key = 0, None
    while heap:
        count, key = heapq.heapreplace(heap, (count, key)) if count else heapq.heappop(heap)
        yield key
        count += 1
    for index in xrange(-count):
        yield key

>>> a = [1,2,3,3,2,2,1]
>>> list(nonadjacent(a))
[2, 1, 2, 3, 1, 2, 3]

পাইথনে অ্যালগরিদম কীভাবে লিখবেন না তার ভাল উদাহরণ। এটি সহজ তবে সিনট্যাক্স হজম করার জন্য 30 মিনিটের মতো প্রয়োজন।
alex904

8

আপনি পুনরাবৃত্তিমূলক ব্যাকট্র্যাকিং অ্যালগরিদম ব্যবহার করে সমস্ত 'নিখুঁতভাবে সাজানো' ক্রম (যে সংলগ্ন অবস্থানে দুটি সমান উপাদান নেই) তৈরি করতে পারেন। প্রকৃতপক্ষে, সমস্ত ক্রম নির্ধারণের একমাত্র পার্থক্য হ'ল আপনি সর্বশেষ সংখ্যাটি লক্ষ্য রাখেন এবং সেই অনুসারে কয়েকটি সমাধান বাদ দেন:

def unsort(lst, last=None):
    if lst:
        for i, e in enumerate(lst):
            if e != last:
                for perm in unsort(lst[:i] + lst[i+1:], e):
                    yield [e] + perm
    else:
        yield []

মনে রাখবেন যে এই ফর্মটিতে ফাংশনটি খুব দক্ষ নয়, কারণ এটি প্রচুর উপ-তালিকা তৈরি করে। এছাড়াও, আমরা প্রথমে সর্বাধিক সীমাবদ্ধ সংখ্যাগুলি (সর্বোচ্চ গণনা সহ) দেখলে এটির গতি বাড়িয়ে তুলতে পারি। এখানে কেবল countsসংখ্যাগুলির ব্যবহার করে আরও কার্যকর সংস্করণ দেওয়া হয়েছে ।

def unsort_generator(lst, sort=False):
    counts = collections.Counter(lst)
    def unsort_inner(remaining, last=None):
        if remaining > 0:
            # most-constrained first, or sorted for pretty-printing?
            items = sorted(counts.items()) if sort else counts.most_common()
            for n, c in items:
                if n != last and c > 0:
                    counts[n] -= 1   # update counts
                    for perm in unsort_inner(remaining - 1, n):
                        yield [n] + perm
                    counts[n] += 1   # revert counts
        else:
            yield []
    return unsort_inner(len(lst))

আপনি এটিকে কেবল nextনিখুঁত ক্রমাঙ্কন তৈরি করতে বা listতাদের সমস্তকে ধরে রাখতে ব্যবহার করতে পারেন । কিন্তু মনে রাখবেন, যদি নেই কোন পুরোপুরি পাঁচমিশালী বিন্যাস, তারপর এই জেনারেটরের পরিণামে সমর্পণ করা হবে কোন ফলাফল নেই।

>>> lst = [1,2,3,3,2,2,1]
>>> next(unsort_generator(lst))
[2, 1, 2, 3, 1, 2, 3]
>>> list(unsort_generator(lst, sort=True))
[[1, 2, 1, 2, 3, 2, 3], 
 ... 36 more ...
 [3, 2, 3, 2, 1, 2, 1]]
>>> next(unsort_generator([1,1,1]))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

এই সমস্যা থেকে রক্ষা পেতে আপনি অন্যান্য উত্তরগুলিতে ফ্যালব্যাক হিসাবে প্রস্তাবিত একটি অ্যালগরিদমের সাথে একত্রে এটি ব্যবহার করতে পারেন। এটি একটি নিখুঁতভাবে অচলিত ক্রিয়াকলাপ ফেরত দেওয়ার গ্যারান্টি দিবে, যদি একটি থাকে, বা অন্যথায় একটি ভাল অনুমানের হয়।

def unsort_safe(lst):
    try:
        return next(unsort_generator(lst))
    except StopIteration:
        return unsort_fallback(lst)

এটি ও (এন ^ 2) মেমরিটি ব্যবহার করে ... ক্রমাগত প্রতিটি উপাদানগুলির জন্য আপনি পুনরাবৃত্ত কলের জন্য তালিকার একটি অনুলিপি করছেন। এছাড়াও, পুনরাবৃত্ত হওয়া, এটি "ছোট" দৈর্ঘ্যের সাথে ব্যর্থ হয়।
বাকুরিউ

@ বাকুরিউ সম্মতি জানালেন, "দক্ষতার জন্য অপ্টিমাইজড নয়" বলতে আমি এটাই বোঝাতে চাইছিলাম ... যদিও আমাকে স্বীকার করতে হবে যে আমি ও (এন ^ 2) স্থান বাদ দিইনি তবে আপনি ঠিক বলেছেন ... আমি এটিকে উন্নত করার চেষ্টা করব ।
tobias_k

ও (এন ion 2) যখন আপনার পুনঃসূচনা হয় তখন সর্বদা পিছনে থাকে T(n+1) = something + T(n)
বাকুরিউ

@ টোবিয়াস_ কে: আপনি কি কেবল একটি পেরামের জন্য কোনও ফাংশন পোস্ট করতে পারবেন, পরীক্ষার জন্য?
জর্জি

@ জর্জি শিওর: next(unsort2(collections.Counter(a)));-) তবে যেহেতু এই অ্যালগো সমস্ত সম্ভাবনা তৈরি করে, কেন সেগুলি সমস্ত পরীক্ষা করে না? এটি 7 টি পরীক্ষামূলক তালিকার জন্য 38 টি।
tobias_k

5

পাইথনে আপনি নিম্নলিখিতগুলি করতে পারেন।

আপনার একটি সাজানো তালিকা রয়েছে তা বিবেচনা করুন l, আপনি এটি করতে পারেন:

length = len(l)
odd_ind = length%2
odd_half = (length - odd_ind)/2
for i in range(odd_half)[::2]:
    my_list[i], my_list[odd_half+odd_ind+i] = my_list[odd_half+odd_ind+i], my_list[i]

এগুলি কেবলমাত্র স্থানের অপারেশনগুলিতে এবং সুতরাং এটির পরিবর্তে দ্রুত হওয়া উচিত ( O(N))। মনে রাখবেন আপনি থেকে নামান হবে l[i] == l[i+1]থেকে l[i] == l[i+2]তাই অর্ডার আপনি দিয়ে শেষ কিন্তু কিছু এলোমেলো হয়ে যায়, কিন্তু কিভাবে আমি প্রশ্নটি বুঝতে থেকে এটা যদৃচ্ছতা নয় তোমার জন্য খুঁজছেন।

ধারণাটি হ'ল মাঝখানে সাজানো তালিকাকে বিভক্ত করে তারপরে প্রতিটি অন্যান্য উপাদানকে দুটি অংশে বিনিময় করতে হবে।

জন্য l= [1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5]এই বিশালাকারl = [3, 1, 4, 2, 5, 1, 3, 1, 4, 2, 5]

l[i] == l[i + 1]তালিকার দৈর্ঘ্যের অর্ধেকের চেয়ে বড় বা সমান উপাদানের প্রাচুর্যের সাথে সাথে পদ্ধতিটি সমস্ত থেকে মুক্তি পেতে ব্যর্থ হয় ।

উপরের অংশটি যতক্ষণ না সর্বাধিক ঘন উপাদানগুলির প্রাচুর্য তালিকার অর্ধেক আকারের চেয়ে ছোট থাকে ততক্ষণ নীচের ফাংশনটি সীমাবদ্ধতার কেসগুলি পরিচালনা করে (বিখ্যাত অফ বাই বাই ইস্যু) যেখানে প্রতিটি অন্যান্য উপাদান দিয়ে শুরু হয় প্রথমটি অবশ্যই সবচেয়ে প্রচুর পরিমাণে হওয়া উচিত:

def no_adjacent(my_list):
    my_list.sort()
    length = len(my_list)
    odd_ind = length%2
    odd_half = (length - odd_ind)/2
    for i in range(odd_half)[::2]:
        my_list[i], my_list[odd_half+odd_ind+i] = my_list[odd_half+odd_ind+i], my_list[i]

    #this is just for the limit case where the abundance of the most frequent is half of the list length
    if max([my_list.count(val) for val in set(my_list)]) + 1 - odd_ind > odd_half:
        max_val = my_list[0]
        max_count = my_list.count(max_val)
        for val in set(my_list):
            if my_list.count(val) > max_count:
               max_val = val
               max_count = my_list.count(max_val)
        while max_val in my_list:
            my_list.remove(max_val)
        out = [max_val]
        max_count -= 1
        for val in my_list:
            out.append(val)
            if max_count:
                out.append(max_val)
                max_count -= 1
        if max_count:
            print 'this is not working'
            return my_list
            #raise Exception('not possible')
        return out
    else:
        return my_list

ধন্যবাদ! এই ব্যর্থ [3, 2, 1, 2, 1, 3, 2](রিটার্ন [2, 1, 3, 1, 2, 2, 3], হওয়া উচিত (3, 2, 1, 2, 1, 3, 2)) - সারকথা দেখতে
গেয়র্গ

@ জর্জি দুঃখিত, আমার খারাপ আমি একটি ভুলে গেছি +1। এখন আবার চেষ্টা করুন।
jojo

এখনো সমস্যা, [1, 3, 3, 3, 3, 1, 1]=>[3, 1, 3, 3, 1, 3, 1]
গেয়র্গ

@ জর্জি যেমন আমি উল্লেখ করেছি, এটি দীর্ঘকাল কাজ করে যতক্ষণ না প্রচুর পরিমাণে এই তালিকার অর্ধ দৈর্ঘ্যের চেয়ে কম উপস্থিত থাকে যা এই উদাহরণে হয় না।
জোজো

@ জর্জি তাই আমি অংশটি একের পর এক ত্রুটি পরিচালনা করেছিলাম। এই অংশটি তাত্পর্যপূর্ণভাবে দ্রুত নয় (থাইজারের প্রস্তাবিত অ্যালগরিদমের মতোই) তবে এটি কেবল বিরল ক্ষেত্রেই চালিত হবে।
জোজো

5

এখানে একটি ভাল অ্যালগরিদম:

  1. সমস্ত সংখ্যার জন্য প্রথমে গণনা করুন যে তারা কতবার ঘটে। উত্তরটি একটি মানচিত্রে রাখুন।

  2. এই মানচিত্রটি বাছাই করুন যাতে বেশিরভাগ সংখ্যকই প্রথমে আসে।

  3. আপনার উত্তরটির প্রথম সংখ্যাটি বাছাই করা মানচিত্রে প্রথম নম্বর।

  4. প্রথমটি এখন আরও ছোট হওয়ায় মানচিত্রটি রিসর্ট করুন।

আপনি যদি দক্ষতা বাড়াতে চান তবে বাছাইকরণ পদক্ষেপের দক্ষতা বাড়ানোর উপায়গুলি সন্ধান করুন।


হ্যাঁ, এটিই টোবিয়াস_ কে করেছে। ভাল কাজ মনে হচ্ছে!
জর্জি

@ জর্জি এটি কিছুটা আলাদা ... আমি কেবলমাত্র জায়গার জটিলতা হ্রাস করতে কাউন্টারটি ব্যবহার করি, তবে আমি কোনও নির্দিষ্ট ক্রম দিয়ে নম্বরগুলি পরীক্ষা করি না (ভেবেছিল এটি সম্ভবত আরও একটি গতি বাড়িয়ে দিতে পারে)। এর চেয়ে আলাদা এটি হ'ল আমার দ্রবণটি সর্বদা সমস্ত 'নিখুঁত' ক্রমানুসন সরবরাহ করে, যদি কোনও হয় তবে এর থেকে সেরা (?) সমাধান পাওয়া যায় (নিখুঁত বা না)।
tobias_k

4
এই সিউডোকোডটি ঠিক ঠিক নয়; যদি আইটেমটি গণনা করা হয় 5 x, 2 y, 2 z, তবে এটি অকারণে x গুলি একসাথে রেখে দেবে। ঠিক করার জন্য আমার উত্তর দেখুন ।
ডেভিড আইজেনস্ট্যাট

4
রাজি। যেমন [1,1,1,2,3] উদাহরণস্বরূপ [1,1,2,1,3] [1,2,1,3,1] এর পরিবর্তে এটি উত্পাদন করবে।
tobias_k

পদক্ষেপ 3 আসলে পাল্টা উত্পাদনশীল। যদি কোনও সংখ্যা সাধারণ হয় (পরবর্তী সর্বাধিক ঘন সংখ্যার চেয়ে কমপক্ষে আরও দুটি এন্ট্রি), তৃতীয় পদক্ষেপটি কোনও যুক্তি ছাড়াই এই সংখ্যাটি পরপর দু'বার ব্যবহার করবে।
এমসাল্টাররা

5

বোনাস প্রশ্নের উত্তরে: এটি একটি অ্যালগরিদম যা কোনও সেটের সমস্ত অনুমোদন খুঁজে পায় যেখানে কোনও সংলগ্ন উপাদান অভিন্ন হতে পারে না। আমি ধারণা করি এটি ধারণাগতভাবে সর্বাধিক দক্ষ অ্যালগরিদম হতে পারে (যদিও অন্যরা অনুশীলনে দ্রুত হতে পারে কারণ তারা সহজ কোডে অনুবাদ করে)। এটি নিষ্ঠুর শক্তি ব্যবহার করে না, এটি কেবল অনন্য ক্রিয়াকলাপ উত্পন্ন করে এবং সমাধানের দিকে পরিচালিত করে না এমন পাথগুলি প্রাথমিক পর্যায়ে কেটে ফেলা হয়।

আমি একটি সেটের একটি উপাদানের জন্য "প্রচুর উপাদান" শব্দটি ব্যবহার করব যা সংশ্লেষিত অন্যান্য সমস্ত উপাদানের তুলনায় প্রায়শই ঘটে এবং প্রচুর পরিমাণে মৌলিক সংখ্যার বিয়োগের জন্য অন্যান্য উপাদানগুলির সংখ্যার জন্য "প্রাচুর্য" শব্দটি ব্যবহৃত হয়।
যেমন সেট abacকোন প্রচুর উপাদান সেট আছে abacaএবং aabcaaআছে aপ্রচুর উপাদান হিসেবে, এবং প্রাচুর্য 1 এবং 2 যথাক্রমে।

  1. এর মতো সেট দিয়ে শুরু করুন:

aaabbcd

  1. পুনরাবৃত্তি থেকে প্রথম ঘটনা পৃথক করুন:

প্রথমত:
অ্যাবসিডি পুনরাবৃত্তি: আব

  1. পুনরাবৃত্তিতে প্রচুর উপাদান সন্ধান করুন, যদি থাকে তবে এবং প্রচুর পরিমাণ গণনা করুন:

প্রচুর উপাদান: একটি
প্রাচুর্য: 1

  1. প্রচুর পরিমাণের পরে উপাদানগুলির সংখ্যা প্রাচুর্যের চেয়ে কম নয় যেখানে আগ্নেয়াস্ত্রগুলির সমস্ত ক্রিয়াকলাপ তৈরি করুন: (উদাহরণস্বরূপ "ক" শেষ হতে পারে না)

এবিসিডি, এবিডিসি, এসিবিডি, এসিডিবি, অ্যাডবিসি, অ্যাডিসিবি, ব্যাক, ব্যাডক , বিসিএডি, বিসিডিএ ,
বিডিএসি, বিডিসিএ, সিবিডি, সিডিবি , সিবিডি, সিবিডি , সিডিবি, সিডিবিএ, ডিবিসি, ডাবিবি , অ্যাব্যাক, ডিবিসিএ , ডিসিবি, ডিসিবিএ

  1. প্রতিটি অনুক্রমের জন্য, এই নিয়মগুলি অনুসরণ করে একের পর এক পুনরাবৃত্ত অক্ষরের সেট সন্নিবেশ করান:

5.1। যদি এতক্ষণে পরমাণুতে প্রচুর পরিমাণে প্রচুর পরিমাণে উপস্থিত হওয়ার পরে সেটটির প্রাচুর্যতা উপাদানের সংখ্যার চেয়ে বেশি হয়, তবে পরবর্তী আদেশে যান।
উদাহরণস্বরূপ abc, এখন পর্যন্ত ক্রমশক্তিটি যখন প্রচুর aপরিমাণে 2 বা তার কম হয় তবে প্রচুর উপাদান সহ একটি সেট কেবল সন্নিবেশ করা যায়, aaaabcঠিক আছে, aaaaabcতাই না।

5.2। সেট থেকে উপাদানটি নির্বাচন করুন যার ক্রমগতিতে সর্বশেষ আসক্তিটি প্রথমে আসে।
উদাহরণস্বরূপ, এখন পর্যন্ত ক্রমশক্তিটি যখন abcbaসেট এবং সেট থাকে তখন abনির্বাচন করুনb

5.3। আদেশে নির্বাচিত উপাদানটির সর্বশেষ উপস্থিতির ডানদিকে কমপক্ষে 2 অবস্থান সন্নিবেশ করান।
যেমন অনুমানের bমধ্যে প্রবেশ করার সময় babca, ফলাফলগুলি হয় babcbaএবংbabcab

5.4। প্রতিটি ফলাফলের অনুমতি এবং সেটটির বাকী অংশের সাথে 5 ধাপ পুনরাবৃত্তি করুন।

EXAMPLE:
set = abcaba
firsts = abc
repeats = aab

perm3  set    select perm4  set    select perm5  set    select perm6

abc    aab    a      abac   ab     b      ababc  a      a      ababac  
                                                               ababca  
                                          abacb  a      a      abacab  
                                                               abacba  
                     abca   ab     b      abcba  a      -
                                          abcab  a      a      abcaba  
acb    aab    a      acab   ab     a      acaba  b      b      acabab  
                     acba   ab     b      acbab  a      a      acbaba  
bac    aab    b      babc   aa     a      babac  a      a      babaca  
                                          babca  a      -
                     bacb   aa     a      bacab  a      a      bacaba  
                                          bacba  a      -  
bca    aab    -
cab    aab    a      caba   ab     b      cabab  a      a      cababa  
cba    aab    -

এই অ্যালগরিদম অনন্য ক্রম উত্পন্ন করে। আপনি যদি ক্রমান্বয়ের মোট সংখ্যা জানতে চান (যেখানে abaআপনি দু'বার গণনা করা হচ্ছে কারণ আপনি একটিটির স্যুইচ করতে পারেন), কোনও ফ্যাক্টরের সাহায্যে অনন্য আদেশের সংখ্যাটি গুণ করুন:

এফ = এন 1 ! * এন 2 ! * ... * এন এন !

যেখানে এন হ'ল সেটে প্রতিটি উপাদানটির সংখ্যার সংখ্যা। একটি সেট জন্য abcdabcabaএই 4 হবে! * 3! * 2! * 1! বা ২৮৮, যা দেখায় যে অ্যালগরিদমটি কতটা অদক্ষ that যা কেবলমাত্র অনন্যের পরিবর্তে সমস্ত ক্রিয়াকলাপ উত্পন্ন করে। এই ক্ষেত্রে সমস্ত ক্রম তালিকাটি তালিকাভুক্ত করতে, কেবল অনন্য অনুমানের তালিকা 288 বার করুন :-)

নীচে জাভাস্ক্রিপ্টে একটি (বরং আনাড়ি) বাস্তবায়ন রয়েছে; আমি সন্দেহ করি পাইথনের মতো কোনও ভাষা এই ধরণের জন্য উপযুক্ত হতে পারে। "অব্র্যাকডাব্র" এর বিভাজন অনুমান গণনা করতে কোড স্নিপেট চালান।

// FIND ALL PERMUTATONS OF A SET WHERE NO ADJACENT ELEMENTS ARE IDENTICAL
function seperatedPermutations(set) {
    var unique = 0, factor = 1, firsts = [], repeats = [], abund;

    seperateRepeats(set);
    abund = abundance(repeats);
    permutateFirsts([], firsts);
    alert("Permutations of [" + set + "]\ntotal: " + (unique * factor) + ", unique: " + unique);

    // SEPERATE REPEATED CHARACTERS AND CALCULATE TOTAL/UNIQUE RATIO
    function seperateRepeats(set) {
        for (var i = 0; i < set.length; i++) {
            var first, elem = set[i];
            if (firsts.indexOf(elem) == -1) firsts.push(elem)
            else if ((first = repeats.indexOf(elem)) == -1) {
                repeats.push(elem);
                factor *= 2;
            } else {
                repeats.splice(first, 0, elem);
                factor *= repeats.lastIndexOf(elem) - first + 2;
            }
        }
    }

    // FIND ALL PERMUTATIONS OF THE FIRSTS USING RECURSION
    function permutateFirsts(perm, set) {
        if (set.length > 0) {
            for (var i = 0; i < set.length; i++) {
                var s = set.slice();
                var e = s.splice(i, 1);
                if (e[0] == abund.elem && s.length < abund.num) continue;
                permutateFirsts(perm.concat(e), s, abund);
            }
        }
        else if (repeats.length > 0) {
            insertRepeats(perm, repeats);
        }
        else {
            document.write(perm + "<BR>");
            ++unique;
        }
    }

    // INSERT REPEATS INTO THE PERMUTATIONS USING RECURSION
    function insertRepeats(perm, set) {
        var abund = abundance(set);
        if (perm.length - perm.lastIndexOf(abund.elem) > abund.num) {
            var sel = selectElement(perm, set);
            var s = set.slice();
            var elem = s.splice(sel, 1)[0];
            for (var i = perm.lastIndexOf(elem) + 2; i <= perm.length; i++) {
                var p = perm.slice();
                p.splice(i, 0, elem);
                if (set.length == 1) {
                    document.write(p + "<BR>");
                    ++unique;
                } else {
                    insertRepeats(p, s);
                }
            }
        }
    }

    // SELECT THE ELEMENT FROM THE SET WHOSE LAST OCCURANCE IN THE PERMUTATION COMES FIRST
    function selectElement(perm, set) {
        var sel, pos, min = perm.length;
        for (var i = 0; i < set.length; i++) {
            pos = perm.lastIndexOf(set[i]);
            if (pos < min) {
                min = pos;
                sel = i;
            }
        }
        return(sel);
    }

    // FIND ABUNDANT ELEMENT AND ABUNDANCE NUMBER
    function abundance(set) {
        if (set.length == 0) return ({elem: null, num: 0});
        var elem = set[0], max = 1, num = 1;
        for (var i = 1; i < set.length; i++) {
            if (set[i] != set[i - 1]) num = 1
            else if (++num > max) {
                max = num;
                elem = set[i];
            }
        }
        return ({elem: elem, num: 2 * max - set.length});
    }
}

seperatedPermutations(["a","b","r","a","c","a","d","a","b","r","a"]);


4
এর জন্য ধন্যবাদ! এটি জাভাস্ক্রিপ্টে কিছুটা ছোট করা যায় কিনা তা দেখতে পাবেন।
stt106

4

ধারণাটি হ'ল উপাদানগুলি সর্বাধিক সাধারণ থেকে সর্বনিম্ন সাধারণের মধ্যে সাজানো, সর্বাধিক সাধারণ হওয়া, এর গণনা হ্রাস করা এবং অবতরণ ক্রম রেখে তালিকায় ফিরিয়ে দেওয়া (তবে শেষের ব্যবহৃত উপাদানটিকে প্রথমে পুনরাবৃত্তি প্রতিরোধ করার জন্য প্রথমে এড়ানো এড়ানো) ।

এটি ব্যবহার করে প্রয়োগ করা যেতে পারে Counterএবং bisect:

from collections import Counter
from bisect import bisect

def unsorted(lst):
    # use elements (-count, item) so bisect will put biggest counts first
    items = [(-count, item) for item, count in Counter(lst).most_common()]
    result = []

    while items:
        count, item = items.pop(0)
        result.append(item)
        if count != -1:
            element = (count + 1, item)
            index = bisect(items, element)
            # prevent insertion in position 0 if there are other items
            items.insert(index or (1 if items else 0), element)

    return result

উদাহরণ

>>> print unsorted([1, 1, 1, 2, 3, 3, 2, 2, 1])
[1, 2, 1, 2, 1, 3, 1, 2, 3]

>>> print unsorted([1, 2, 3, 2, 3, 2, 2])
[2, 3, 2, 1, 2, 3, 2]

এটি ব্যর্থ হয়, উদাহরণস্বরূপ: [1, 1, 2, 3]যেখানে সমাধান যেমন রয়েছে [1, 2, 1, 3]
বাকুরিউ

হ্যাঁ, আমি ঠিক বুঝতে পেরেছি, দুঃখিত
enrico.bacis

ধন্যবাদ! এটি সর্বদা অনুকূল ফলাফল তৈরি করে না, উদাহরণস্বরূপ [1, 2, 3, 2, 3, 2, 2]এটির [2, 3, 1, 2, 3, 2, 2](1 ত্রুটি) ফিরে আসে , যদিও আদর্শটি হয় (2, 1, 2, 3, 2, 3, 2)) - সংক্ষিপ্ত বিবরণ দেখুন।
জর্জি

@ জর্জি সত্য, দুর্দান্ত ক্যাচ, আমি এটি ব্যবহার করি এমন সাধারণ নীতিটি রেখে আপডেট করেছি।
enrico.bacis

@ এনরিকো.ব্যাকিস: ধন্যবাদ! নতুন সংস্করণ নির্দ্বিধায় কাজ করে। আমি সারাংশ আপডেট করেছি খুব খারাপ আমি তোমাকে আর উজ্জীবিত করতে পারি না।
জর্জি

2
  1. তালিকাটি বাছাই করুন।
  2. এই অ্যালগরিদমটি ব্যবহার করে তালিকার একটি "সেরা সাফল্য" তৈরি করুন

এটি তালিকা থেকে সর্বনিম্ন আইটেমগুলিকে তাদের মূল স্থানে (আইটেমের মান দ্বারা) দেবে তাই এটি চেষ্টা করবে, উদাহরণস্বরূপ, 1 এর, 2 এবং 3 এর সর্ট অবস্থান থেকে দূরে রাখার চেষ্টা করবে।


আমি চেষ্টা করেছি best_shuffleএবং এটি উত্পন্ন হয়েছে [1,1,1,2,3] -> [3, 1, 2, 1, 1]- আদর্শ নয়!
জর্জি

2

দৈর্ঘ্যের অনুসারে বাছাই করা তালিকা দিয়ে শুরু করুন। চলুন মি = এন / 2। 0, তার পরে মি, তারপরে 1, তার পরে মি + 1, তারপরে 2, তার পরে মি + 2 এবং আরও কিছুতে মান ধরুন। আপনার অর্ধেকের বেশি সংখ্যার সমান না হলে আপনি একটানা ক্রমে কখনও সমমানের মান পাবেন না।


ধারণার জন্য ধন্যবাদ। আমি মনে করি @ হিউস্টার এটি প্রয়োগ করেছেন।
জর্জি

2

দয়া করে আমার "আমিও" স্টাইলের উত্তরটি ক্ষমা করুন, তবে কোডির উত্তরটি কী এটিকে সহজ করা যায় না?

from collections import Counter
from heapq import heapify, heappop, heapreplace
from itertools import repeat

def srgerg(data):
    heap = [(-freq+1, value) for value, freq in Counter(data).items()]
    heapify(heap)

    freq = 0
    while heap:
        freq, val = heapreplace(heap, (freq+1, val)) if freq else heappop(heap)
        yield val
    yield from repeat(val, -freq)

সম্পাদনা করুন: এখানে একটি অজগর 2 সংস্করণ রয়েছে যা একটি তালিকা প্রত্যাবর্তন করে:

def srgergpy2(data):
    heap = [(-freq+1, value) for value, freq in Counter(data).items()]
    heapify(heap)

    freq = 0
    result = list()
    while heap:
        freq, val = heapreplace(heap, (freq+1, val)) if freq else heappop(heap)
        result.append(val)
    result.extend(repeat(val, -freq))
    return result

হ্যাঁ, এটি ঠিকঠাক কাজ করছে বলে মনে হচ্ছে (আমি পিআই 2 এ আছি এবং ফাংশনটির একটি তালিকা ফেরত দেওয়া উচিত)।
জর্জি

@ জর্জি ওকে, আমি পাইথন 2 সংস্করণ যুক্ত করেছি যা একটি তালিকা ফিরে আসে।

2
  1. প্রতিটি মান প্রদর্শিত হওয়ার সময় গণনা করুন
  2. সর্বাধিক ঘন থেকে কমপক্ষে ঘন ঘন থেকে ক্রমানুসারে মান নির্বাচন করুন
  3. চূড়ান্ত আউটপুটে নির্বাচিত মান যুক্ত করুন, প্রতিবার সূচককে 2 দ্বারা বাড়িয়ে তুলুন
  4. সীমা ছাড়িয়ে গেলে সূচকে 1 এ রিসেট করুন
from heapq import heapify, heappop
def distribute(values):
    counts = defaultdict(int)
    for value in values:
        counts[value] += 1
    counts = [(-count, key) for key, count in counts.iteritems()]
    heapify(counts)
    index = 0
    length = len(values)
    distributed = [None] * length
    while counts:
        count, value = heappop(counts)
        for _ in xrange(-count):
            distributed[index] = value
            index = index + 2 if index + 2 < length else 1
    return distributed
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.