2008-08-03 11 views
16

आपके पास संख्याओं की एक आरोही सूची है, जो कि सबसे कुशल एल्गोरिदम है जो आप उस सूची में प्रत्येक दो संख्याओं की रकम की आरोही सूची प्राप्त करने के बारे में सोच सकते हैं। परिणामस्वरूप सूची में डुप्लिकेट अप्रासंगिक हैं, यदि आप चाहें तो उन्हें हटा सकते हैं या उनसे बच सकते हैं।कुशलता से सॉर्ट की गई सूची की क्रमबद्ध रकम प्राप्त करें

स्पष्ट होने के लिए, मुझे एल्गोरिदम में रूचि है। किसी भी भाषा और प्रतिमान में कोड पोस्ट करने के लिए स्वतंत्र महसूस करें।

उत्तर

12

2018 के रूप में संपादित करें: आपको शायद इसे पढ़ना बंद कर देना चाहिए। (लेकिन मैं इसे हटा सकते हैं नहीं के रूप में यह स्वीकार किया जाता है।)

अगर आप इस तरह रकम लिखने:

1 4 5 6 8 9 
--------------- 
2 5 6 7 9 10 
    8 9 10 12 13 
    10 11 13 14 
     12 14 15 
      16 17 
      18 

आपको पता चलेगा कि के बाद से एम [i, j] < = एम [ i, j + 1] और एम [i, j] < = एम [i + 1, j], तो आपको केवल शीर्ष बाएं "कोनों" की जांच करने और सबसे कम चुनने की आवश्यकता है।

उदा।

  • केवल 1 ऊपरी बाएं कोने,,, लेने 2
  • केवल 1, 5
  • 6 या 8 लेने लेने 6
  • 7 या 8, 7
  • 9 या 8 लेने 8
  • लेने
  • 9 या 9, लेने दोनों :)
  • 10 या 10 या 10, लेने सभी
  • 12 या 11, लेने 11
  • 12 या 12, लेने दोनों
  • 13 या 13, लेने दोनों
  • 14 या 14, लेने दोनों
  • 15 या 16, लेने 15
  • केवल 1, 16
  • केवल 1 लेने, 17 लेने
  • केवल 1, 18
बेशक

लेने, आप बहुत ऊपरी बाएं कोने में तो इस समाधान devolves है जब।

मैं पूरी तरह से सुनिश्चित इस समस्या Ω (n²) है कर रहा हूँ क्योंकि आप प्रत्येक M के लिए रकम की गणना करने के [i, j] है - जब तक कि कोई योग :)

+1

मुझे लगता है कि यह ओ (एन^3) है क्योंकि प्रत्येक चरण में एन संभावित 'टॉप बाएं कोनों' हैं। –

+2

आप प्राथमिकता कतार में प्रत्येक पंक्ति में पहली अनपढ़ प्रविष्टि को संग्रहीत करके ओ (एन^2 लॉग एन) समय में इस एल्गोरिदम को कार्यान्वित कर सकते हैं, लेकिन असम्बद्ध रूप से यह सभी रकम और सॉर्टिंग उत्पन्न करने से बेहतर नहीं है। –

+0

यदि आपके पास एक के बजाय दो सूचियां हैं, लंबाई एम और एन के साथ एम dfeuer

-4

यदि आप वास्तव में भाषा अज्ञेय समाधान की तलाश में हैं तो आप मेरी राय में बहुत निराश होंगे क्योंकि आप लूप और कुछ सशर्तों के साथ फंस जाएंगे। हालांकि अगर आपने इसे कार्यात्मक भाषाओं या कार्यात्मक भाषा विशेषताओं तक खोल दिया है (मैं आपको LINQ देख रहा हूं) तो मेरे सहयोगी यहां इस पृष्ठ को रूबी, लिस्प, एरलांग और अन्य में सुरुचिपूर्ण उदाहरणों से भर सकते हैं।

1

सबसे अच्छा मैं साथ आ सकता हूं कि प्रत्येक जोड़ी की रकम का मैट्रिक्स तैयार किया जाए, और फिर पंक्तियों को एक साथ लाएं, एक ला मर्ज सॉर्ट करें। मुझे लगता है कि मुझे कुछ सरल अंतर्दृष्टि याद आ रही है जो एक अधिक कुशल समाधान प्रकट करेगी।

मेरे एल्गोरिथ्म, हास्केल में:

matrixOfSums list = [[a+b | b <- list, b >= a] | a <- list] 

sortedSums = foldl merge [] matrixOfSums 

--A normal merge, save that we remove duplicates 
merge xs [] = xs 
merge [] ys = ys 
merge (x:xs) (y:ys) = case compare x y of 
    LT -> x:(merge xs (y:ys)) 
    EQ -> x:(merge xs (dropWhile (==x) ys)) 
    GT -> y:(merge (x:xs) ys) 

मैं एक छोटी सी सुधार, एक है कि आलसी धारा आधारित कोडिंग के लिए और अधिक उत्तरदायी है पाया। कॉलम जोड़ी के अनुसार विलय करने के बजाय, उन सभी को एक साथ मिलाएं। लाभ यह है कि आप तुरंत सूची के तत्व प्राप्त करना शुरू करते हैं।

-- wide-merge does a standard merge (ala merge-sort) across an arbitrary number of lists 
-- wideNubMerge does this while eliminating duplicates 
wideNubMerge :: Ord a => [[a]] -> [a] 
wideNubMerge ls = wideNubMerge1 $ filter (/= []) ls 
wideNubMerge1 [] = [] 
wideNubMerge1 ls = mini:(wideNubMerge rest) 
    where mini = minimum $ map head ls 
      rest = map (dropWhile (== mini)) ls 

betterSortedSums = wideNubMerge matrixOfSums 

हालांकि, अगर आप जानते हैं कि आप रकम का उपयोग करने जा रहे हैं, और उनमें से पहले कुछ हो रही करने के लिए कोई लाभ है, 'foldl merge []' के साथ जाने के रूप में यह सबसे तेज़ है।

+0

मुझे लगता है (मेरा हैकेल जंगली है) यह ओ (एन^3) है क्योंकि परिणामस्वरूप प्रत्येक चीज के लिए ओ (एन) तुलना की जाती है। –

4

इसे कोड करने के बजाय, मुझे लगता है कि मैं इसे चरणों में छद्म कोड दूंगा और अपने तर्क की व्याख्या करूंगा, ताकि बेहतर प्रोग्रामर आवश्यक होने पर मेरे तर्क में छेद लगा सकें।

पहले चरण पर हम संख्या लंबाई की सूची के साथ शुरू करते हैं n। प्रत्येक संख्या के लिए हमें लंबाई एन -1 की एक सूची बनाने की आवश्यकता है क्योंकि हम स्वयं को एक संख्या नहीं जोड़ रहे हैं। अंत में हमारे पास ओ (एन^2) समय में जेनरेट की गई एन सॉर्टेड सूचियों की एक सूची है।

step 1 (startinglist) 
for each number num1 in startinglist 
    for each number num2 in startinglist 
     add num1 plus num2 into templist 
    add templist to sumlist 
return sumlist 

चरण 2 में, क्योंकि सूचियों डिजाइन के अनुसार क्रमबद्ध किया गया (एक क्रमबद्ध सूची में प्रत्येक तत्व में नंबर जोड़ने और सूची अभी भी हल हो जाएगा) हम केवल एक mergesort कर सकते हैं एक साथ प्रत्येक सूची विलय के बजाय mergesorting द्वारा पूरा बहुत अंत में यह ओ (एन^2) समय लेना चाहिए।

step 2 (sumlist) 
create an empty list mergedlist 
for each list templist in sumlist 
    set mergelist equal to: merge(mergedlist,templist) 
return mergedlist 

मर्ज विधि तब जांच के साथ सामान्य विलय चरण होगा ताकि यह सुनिश्चित किया जा सके कि कोई डुप्लिकेट रकम नहीं है। मैं इसे नहीं लिखूंगा क्योंकि कोई भी विलय को देख सकता है।

तो मेरा समाधान है। संपूर्ण एल्गोरिदम ओ (एन^2) समय है। किसी भी गलतियों या सुधारों को इंगित करने के लिए स्वतंत्र महसूस करें।

+0

मुझे लगता है कि यह ओ (एन^3) है क्योंकि चरण 2 में प्रत्येक चरण में एन तुलनाएं हैं। –

1

एसक्यूएल में:

create table numbers(n int not null) 
insert into numbers(n) values(1),(1), (2), (2), (3), (4) 


select distinct num1.n+num2.n sum2n 
from numbers num1 
inner join numbers num2 
    on num1.n<>num2.n 
order by sum2n 

सी # LINQ:

List<int> num = new List<int>{ 1, 1, 2, 2, 3, 4}; 
var uNum = num.Distinct().ToList(); 
var sums=(from num1 in uNum 
     from num2 in uNum 
     where num1!=num2 
     select num1+num2).Distinct(); 
foreach (var s in sums) 
{ 
    Console.WriteLine(s); 
} 
2

आप

allSums = set(a+b for a in X for b in X) 
allSums = sorted(allSums) 

इस की लागत के साथ अजगर में दो पंक्तियों में ऐसा कर सकते हैं n^2 है (शायद सेट के लिए एक अतिरिक्त लॉग कारक है?) सॉर्टिंग के लिए पुनरावृत्ति और एस * लॉग (एस) के लिए सेट का आकार कहां है।

सेट का आकार एन * (एन -1)/2 के रूप में बड़ा हो सकता है उदाहरण के लिए यदि एक्स = [1,2,4, ..., 2^n]। इसलिए यदि आप इस सूची को उत्पन्न करना चाहते हैं तो यह सबसे खराब मामले में कम से कम n^2/2 लेगा क्योंकि यह आउटपुट का आकार है।

लेकिन यदि आप ओ (केएन) में परिणाम की पहली कश्मीर तत्वों आप यह कर सकते हैं का चयन करने के फ्रेडेरिकक्सों और जॉनसन (see here for gory details) के अनुसार क्रमबद्ध X + Y मैट्रिक्स के लिए एक चयन कलन विधि का उपयोग करना चाहते हैं। हालांकि यह शायद करने के लिए संशोधित किया जा सकता गणना पुन: उपयोग से उन्हें ऑनलाइन पैदा करते हैं और इस सेट के लिए एक कुशल जनरेटर मिलता है।

@deuseldorf, पीटर वहाँ के बारे में कुछ भ्रम की स्थिति (एन!) है मैं गंभीरता से संदेह deuseldorf मतलब था "एन तथ्यात्मक" लेकिन बस "एन, (बहुत उत्साहित)! "

+0

मेरे पास अन्य सभी समाधानों की तुलना में बेहतर जटिलता है! O (n^2.log (एन))। यह भी सबसे अधिक पढ़ने योग्य और सबसे छोटा है। –

1

यह प्रश्न मेरे दिमाग को लगभग एक दिन के लिए तोड़ रहा है। बहुत बढ़िया।

वैसे भी, आप आसानी से एन^2 प्रकृति से दूर नहीं जा सकते हैं, लेकिन आप मर्ज के साथ थोड़ा बेहतर कर सकते हैं क्योंकि आप प्रत्येक तत्व को सम्मिलित करने के लिए सीमा को बाध्य कर सकते हैं।

यदि आप सभी को देखते हैं

(a[i], a[j]) | j>=i

आप इसे फ्लिप 90 डिग्री, तो आप मिल: सूचियों आप उत्पन्न, वे निम्नलिखित रूप है

(a[i], a[j]) | i<=j

अब, टी वह विलय प्रक्रिया दो सूचियों i और i+1 (जो सूचियों के अनुरूप जहां पहले सदस्य हमेशा होता है a[i] और a[i+1]) ले जा किया जाना चाहिए, आप सूची i में (a[i], a[j]) के स्थान और (a[i + 1], a[j + 1]) के स्थान के आधार तत्व (a[i + 1], a[j]) सम्मिलित करने के लिए सीमा के लिए बाध्य कर सकते हैं।

इसका मतलब है कि आपको j के संदर्भ में उलटा होना चाहिए। मुझे नहीं पता (अभी तक) यदि आप j पर भी इसका लाभ उठा सकते हैं, लेकिन ऐसा लगता है।

1

के लिए एक बेहतर एल्गोरिथ्म है कोई इनपुट मानों पर अतिरिक्त बाधाओं के बिना आप क्या करते हैं, आप ओ (एन^2) से बेहतर नहीं कर सकते हैं, क्योंकि आपको संख्याओं के सभी जोड़ों के माध्यम से फिर से शुरू करना है। पुनरावृत्ति सॉर्टिंग पर हावी रहेगा (जिसे आप ओ (एन लॉग एन) या तेज में कर सकते हैं)।

+1

हां, लेकिन n^2 चीजों को सॉर्ट करने के लिए ओ (एन^2 लॉग एन) लेता है ताकि सॉर्टिंग कभी प्रभावित न हो। –

संबंधित मुद्दे