1 बिलियन नंबरों की एक सरणी से 100 सबसे बड़ी संख्याओं को खोजने के लिए एक प्रोग्राम लिखें


300

मैंने हाल ही में एक साक्षात्कार में भाग लिया, जहां मुझसे पूछा गया कि "1 बिलियन नंबरों की एक सरणी से 100 सबसे बड़ी संख्याओं को खोजने के लिए एक कार्यक्रम लिखें।"

मैं केवल ब्रूट फोर्स सॉल्यूशन देने में सक्षम था जो कि ओ (नॉग्लन) टाइम जटिलता में सरणी को सॉर्ट करने और अंतिम 100 नंबर लेने में सक्षम था।

Arrays.sort(array);

साक्षात्कारकर्ता एक बेहतर समय जटिलता की तलाश में था, मैंने कुछ अन्य समाधानों की कोशिश की लेकिन उसका जवाब देने में विफल रहा। क्या एक बेहतर समय जटिलता समाधान है?


70
शायद समस्या यह है कि यह एक छंटाई का सवाल नहीं था , लेकिन एक चाहने वाला था।
जियोमागास

11
एक तकनीकी नोट के रूप में, समस्या को हल करने का सबसे अच्छा तरीका नहीं हो सकता है, लेकिन मुझे नहीं लगता कि यह क्रूरता है - मैं इसे करने के बहुत बुरे तरीकों के बारे में सोच सकता हूं।
बर्नहार्ड बार्कर

88
मैंने सिर्फ एक और अधिक बेवकूफ जानवर बल विधि के बारे में सोचा ... 1 अरब तत्व सरणी से 100 तत्वों के सभी संभावित संयोजनों को ढूंढें और देखें कि इनमें से किस संयोजन में सबसे बड़ा योग है।
शशांक

10
ध्यान दें कि सभी निर्धारक (और सही) एल्गोरिदम O(1)इस मामले में हैं, क्योंकि कोई आयाम वृद्धि नहीं है। साक्षात्कारकर्ता को पूछा जाना चाहिए कि "n के साथ n के सरणी से m सबसे बड़े तत्वों को कैसे खोजना है?"
बकुरीउ

जवाबों:


328

आप 100 सबसे बड़ी संख्याओं में से एक प्राथमिकता कतार रख सकते हैं, अरब संख्याओं के माध्यम से पुनरावृति, जब भी आप कतार में सबसे छोटी संख्या (कतार के प्रमुख) से अधिक संख्या का सामना करते हैं, कतार के सिर को हटा दें और नया नंबर जोड़ें कतार में।

EDIT: जैसा कि देव ने उल्लेख किया है, एक प्राथमिकता के साथ एक ढेर के साथ लागू की गई कतार में सम्मिलन की जटिलता हैO(logN)

सबसे खराब स्थिति में आपको मिलता है जो कि बेहतर हैbillionlog2(100)billionlog2(billion)

सामान्य तौर पर, यदि आपको N नंबर के सेट से सबसे बड़े K नंबर की आवश्यकता है, तो जटिलता इसके O(NlogK)बजाय है O(NlogN), यह बहुत महत्वपूर्ण हो सकता है जब K, N की तुलना में बहुत छोटा है।

EDIT2:

इस एल्गोरिथ्म का अपेक्षित समय काफी दिलचस्प है, क्योंकि प्रत्येक पुनरावृत्ति में एक सम्मिलन हो सकता है या नहीं हो सकता है। I'th नंबर को कतार में डालने की संभावना एक यादृच्छिक चर की संभावना है i-Kजो समान वितरण से कम से कम यादृच्छिक चर से बड़ा होता है (पहले k संख्या स्वचालित रूप से कतार में जोड़े जाते हैं)। हम इस संभाव्यता की गणना करने के लिए ऑर्डर आँकड़े ( लिंक देखें ) का उपयोग कर सकते हैं । उदाहरण के लिए, मान लेते हैं कि संख्याओं को यादृच्छिक रूप से समान रूप से चुना गया था {0, 1}, (iK) वें नंबर (i संख्याओं में से) का अपेक्षित मान है (i-k)/i, और यादृच्छिक चर के इस मान से बड़ा होने की संभावना है 1-[(i-k)/i] = k/i

इस प्रकार, आवेषण की अपेक्षित संख्या है:

यहां छवि विवरण दर्ज करें

और अपेक्षित रनिंग टाइम के रूप में व्यक्त किया जा सकता है:

यहां छवि विवरण दर्ज करें

( kपहले kतत्वों के साथ कतार उत्पन्न करने का समय , फिर n-kतुलना, और ऊपर वर्णित सम्मिलन की अपेक्षित संख्या, प्रत्येक को औसतन लेता है log(k)/2)

ध्यान दें कि कब Nकी तुलना बहुत बड़ी है K, यह अभिव्यक्ति nइसके बजाय बहुत करीब है NlogK। यह कुछ हद तक सहज है, जैसा कि प्रश्न के मामले में, 10000 पुनरावृत्तियों (जो कि एक अरब की तुलना में बहुत कम है) के बाद भी, एक संख्या को कतार में सम्मिलित करने की संभावना बहुत कम है।


6
यह वास्तव में प्रत्येक डालने के लिए केवल ओ (100) है
MrSmith42

8
@ रॉनटेलर आप एक लिंक की गई सूची को कुशलता से खोज नहीं सकते हैं, यही वजह है कि आमतौर पर एक प्राथमिकता कतार ढेर के साथ लागू की जाती है। वर्णित के रूप में आपका सम्मिलन समय O (n) नहीं है O (logn) है। जब तक स्केज़ ने आपको दूसरा अनुमान नहीं लगाया, तब तक आपके पास पहली बार (कतार या प्राथमिकता कतार का आदेश दिया गया) सही था।
देव

17
@ThomasJungblut बिलियन भी एक स्थिर है, इसलिए यदि ऐसा है तो O (1): P
रॉन टेलर

9
@ रॉनटेलर: आम तौर पर इस तरह के सवाल चिंता के बारे में सोचते हैं जैसे अरबों Google खोज परिणामों में से 10 शीर्ष पृष्ठ, या किसी शब्द क्लाउड के लिए 50 सबसे लगातार शब्द, या एमटीवी पर 10 सबसे लोकप्रिय गीत, आदि, इसलिए, मेरा मानना ​​है कि सामान्य परिस्थितियों में। इसकी तुलना में k निरंतर और छोटे विचार करना सुरक्षित है n। हालांकि, एक को हमेशा इस "सामान्य परिस्थितियों" को ध्यान में रखना चाहिए।
मित्र

5
चूँकि आपके पास 1G आइटम हैं, 1000 तत्वों को बेतरतीब ढंग से सैंपल करें, और सबसे बड़ा 100 चुनें। कि पतित मामलों की संख्या से बचना चाहिए (क्रमबद्ध, रिवर्स सॉर्ट किए गए, ज्यादातर सॉर्ट किए गए), आवेषण की संख्या को काफी कम करना।
ChuckCottrill

136

यदि यह एक साक्षात्कार में पूछा जाता है, मुझे लगता है कि साक्षात्कारकर्ता शायद आपकी समस्या को हल करने की प्रक्रिया को देखना चाहता है, न कि आपके एल्गोरिदम का ज्ञान।

वर्णन काफी सामान्य है इसलिए शायद आप समस्या को स्पष्ट करने के लिए उससे इन संख्याओं की सीमा या अर्थ पूछ सकते हैं। ऐसा करने से साक्षात्कारकर्ता प्रभावित हो सकता है। यदि, उदाहरण के लिए, ये संख्या किसी देश (जैसे चीन) के लोगों की उम्र के लिए है, तो यह बहुत आसान समस्या है। एक उचित धारणा के साथ कि कोई भी जीवित 200 वर्ष से अधिक उम्र का नहीं है, आप केवल एक पुनरावृत्ति में समान आयु वाले लोगों की संख्या की गणना करने के लिए आकार 200 (शायद 201) के अंतर सरणी का उपयोग कर सकते हैं। यहां सूचकांक का मतलब उम्र है। इसके बाद यह 100 सबसे बड़ी संख्या खोजने के लिए केक का एक टुकड़ा है। वैसे इस एल्गो को काउंटिंग सॉर्ट कहा जाता है ।

वैसे भी, एक साक्षात्कार में प्रश्न को अधिक विशिष्ट और स्पष्ट बनाना आपके लिए अच्छा है।


26
बहुत अच्छे अंक। उन नंबरों के वितरण के बारे में किसी और ने कुछ भी नहीं पूछा या संकेत नहीं दिया - यह समस्या के दृष्टिकोण में सभी अंतर बना सकता है।
नीलबी

13
मैं यह उत्तर देना चाहूंगा कि इसे बढ़ाया जाए। न्यूनतम / अधिकतम मान प्राप्त करने के लिए एक बार संख्याओं को पढ़ें ताकि आप वितरण को मान सकें। फिर, दो विकल्पों में से एक ले लो। यदि सीमा काफी छोटी है, तो एक सरणी बनाएं जहां आप संख्याओं की जांच कर सकते हैं जैसे वे होते हैं। यदि सीमा बहुत बड़ी है, तो ऊपर चर्चा की गई छंटनी हीप एल्गोरिथ्म का उपयोग करें .... बस एक विचार।
रिचर्ड_ जी

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

1
@R_G को पूरी सूची से गुजरने की आवश्यकता नहीं है। उपयोगी आंकड़े प्राप्त करने के लिए सूची के यादृच्छिक सदस्यों के एक छोटे अंश (जैसे, एक मिलियन) का नमूना लेने के लिए पर्याप्त है।
इटमार

उन लोगों के लिए, जिन्होंने उस समाधान के बारे में नहीं सोचा होगा, मैं काउंटिंग के बारे में पढ़ना चाहता हूँ en.wikipedia.org/wiki/Counting_sort । यह वास्तव में एक बहुत ही सामान्य साक्षात्कार प्रश्न है: क्या आप किसी सरणी को O (nlogn) से बेहतर कर सकते हैं। यह सवाल सिर्फ एक विस्तार है।
मैक्सिम चेरमी

69

आप उन संख्याओं पर पुनरावृति कर सकते हैं जो O (n) लेती हैं

जब भी आपको वर्तमान न्यूनतम से अधिक मूल्य मिले, नए मान को आकार 100 के साथ एक गोलाकार कतार में जोड़ें।

उस गोलाकार कतार का न्यूनतम मूल्य आपके नए तुलनात्मक मूल्य है। उस कतार में शामिल होते रहें। यदि पूर्ण हो, तो कतार से न्यूनतम निकालें।


3
यह काम नहीं करता है। उदाहरण के लिए {1, 100, 2, 99} के शीर्ष 2 को शीर्ष 2 के रूप में {100,1} देंगे,
स्किज़

7
आप पंक्तिबद्ध कतार को पकड़ने के लिए इधर-उधर नहीं जा सकते। (यदि आप अगले सबसे छोटे तत्व के लिए हर बार छेद की कतार नहीं खोजना चाहते हैं)
MrSmith42

3
@ MrSmith42 आंशिक छँटाई, एक ढेर के रूप में, पर्याप्त है। रॉन टेलर का उत्तर देखें।
क्रिस्टोफर क्रुट्ज़िग

1
हां, मैंने चुपचाप यह मान लिया था कि एक अर्क-मिन-क्यू को ढेर के रूप में लागू किया गया है।
रेन्ग्नेशिन

आकार की परिपत्र कतार के बजाय आकार 100 के न्यूनतम ढेर का उपयोग करें, यह शीर्ष पर न्यूनतम सौ नंबर होगा। यह कतार के मामले में o (n) की तुलना में डालने के लिए केवल O (लॉग एन)
लेगा

33

मैंने महसूस किया कि यह 'एल्गोरिथ्म' के साथ टैग किया गया है, लेकिन कुछ अन्य विकल्पों को टॉस करेगा, क्योंकि संभवतः इसे 'साक्षात्कार' भी टैग किया जाना चाहिए।

1 बिलियन नंबरों का स्रोत क्या है? यदि यह एक डेटाबेस है तो 'टेबल ऑर्डर फ्रॉम टेबल ऑर्डर बाइ वैल्यू डीएससी लिमिट 100' काम को काफी अच्छी तरह से करेगा - इसमें डायलिसिस अंतर हो सकता है।

क्या यह एकबारगी है, या कुछ ऐसा है जो दोहराया जाएगा? अगर दोहराया जाए तो कितनी बार? यदि यह एक-बंद है और डेटा किसी फ़ाइल में है, तो 'cat srcfile | सॉर्ट (विकल्प आवश्यकतानुसार) | हेड -100 'में आपको जल्दी से उत्पादक कार्य करने होंगे जो आपको भुगतान करने के लिए मिल रहे हैं जबकि कंप्यूटर इस तुच्छ काम को संभालता है।

यदि यह दोहराया जाता है, तो आप प्रारंभिक उत्तर प्राप्त करने और परिणामों को संग्रहीत / कैश करने के लिए किसी भी सभ्य दृष्टिकोण को चुनने की सलाह देंगे ताकि आप लगातार शीर्ष 100 की रिपोर्ट करने में सक्षम हो सकें।

अंत में, यह विचार है। क्या आप एक प्रवेश स्तर की नौकरी की तलाश कर रहे हैं और एक geeky प्रबंधक या भविष्य के सहकर्मी के साथ साक्षात्कार कर रहे हैं? यदि ऐसा है, तो आप रिश्तेदार तकनीकी पेशेवरों और विपक्षों का वर्णन करने के सभी तरीकों को टॉस कर सकते हैं। यदि आप एक अधिक प्रबंधकीय नौकरी की तलाश कर रहे हैं, तो समाधान के विकास और रखरखाव की लागत से संबंधित एक प्रबंधक से संपर्क करें, और कहें कि "बहुत-बहुत धन्यवाद" और छोड़ दें यदि साक्षात्कारकर्ता सीएस ट्रिविया पर ध्यान केंद्रित करना चाहता है। । उसके और आपके पास वहां उन्नति की संभावना नहीं होगी।

अगले साक्षात्कार पर बेहतर भाग्य।


2
असाधारण उत्तर। बाकी सभी ने सवाल के तकनीकी पक्ष पर ध्यान केंद्रित किया है, जबकि यह प्रतिक्रिया इसके व्यापार के सामाजिक हिस्से से निपटती है।
vbocan

2
मैंने कभी नहीं सोचा था कि आप धन्यवाद कह सकते हैं और एक साक्षात्कार छोड़ सकते हैं और इसके खत्म होने का इंतजार नहीं कर सकते। मेरा दिमाग खोलने के लिए धन्यवाद।
उर्सुलरासू

1
हम अरब तत्वों का ढेर क्यों नहीं बना सकते और 100 सबसे बड़े तत्वों को निकाल सकते हैं। इस तरह लागत = O (बिलियन) + 100 * O (लॉग (बिलियन)) ??
मोहित शाह

17

इसके लिए मेरी तत्काल प्रतिक्रिया एक ढेर का उपयोग करना होगी, लेकिन किसी भी एक समय पर सभी इनपुट मूल्यों को हाथ में रखे बिना क्विकसेल का उपयोग करने का तरीका है।

आकार 200 की एक सरणी बनाएं और इसे पहले 200 इनपुट मानों के साथ भरें। QuickSelect चलाएं और कम 100 को त्यागें, आपको 100 मुक्त स्थानों के साथ छोड़ दें। अगले 100 इनपुट मानों में पढ़ें और फिर से QuickSelect चलाएं। तब तक जारी रखें जब तक कि आप पूरे इनपुट को 100 के बैच में न चला लें।

अंत में आपके पास शीर्ष 100 मान हैं। N मानों के लिए आपने QuickSelect को लगभग N / 100 बार चलाया है। प्रत्येक क्विकसेले की लागत लगभग 200 गुना है, इसलिए कुल लागत 2N गुना कुछ स्थिर है। यह मेरे लिए इनपुट के आकार में रैखिक दिखता है, पैरामीटर आकार की परवाह किए बिना कि मैं इस स्पष्टीकरण में 100 होने के लिए सख्त हूं।


10
आप एक छोटा लेकिन संभवतः महत्वपूर्ण अनुकूलन जोड़ सकते हैं: आकार 200 सरणी को विभाजित करने के लिए क्विकसेलेक्ट चलाने के बाद, शीर्ष 100 तत्वों में से न्यूनतम ज्ञात है। फिर, पूरे डेटा सेट पर पुनरावृत्ति करते समय, केवल 100 मान कम करें यदि वर्तमान मान वर्तमान न्यूनतम से अधिक है। C ++ में इस एल्गोरिथ्म का एक सरल कार्यान्वयन libstdc ++ के साथ partial_sortसीधे 200 मिलियन 32-बिट int(एक MT19937 के माध्यम से बनाया गया, समान रूप से वितरित) पर चलाया जाता है।
dyp

1
अच्छा विचार - सबसे बुरे मामले के विश्लेषण को प्रभावित नहीं करता है, लेकिन अच्छी तरह से करने योग्य लगता है।
mcdowella

@mcdowella यह एक कोशिश के काबिल है और मैं इसे करूँगा, धन्यवाद!
userx

8
यह अमरूद का ठीक वैसा Ordering.greatestOf(Iterable, int)ही है। यह बिल्कुल रैखिक-समय और एकल-पास है, और यह एक सुपर प्यारा एल्गोरिथ्म है। एफडब्ल्यूआईडब्ल्यू, हमारे पास कुछ वास्तविक बेंचमार्क भी हैं: इसके निरंतर कारक औसत मामले में पारंपरिक प्राथमिकता कतार की तुलना में एक बाल धीमे हैं, लेकिन यह कार्यान्वयन "सबसे खराब स्थिति" इनपुट (जैसे कड़ाई से आरोही इनपुट) के लिए अधिक प्रतिरोधी है।
लुई वासरमैन

15

आप (क्रम से) सूचकांक [बिलियन -१०१] पर संख्या ज्ञात करने के लिए क्विक सिलेक्ट एल्गोरिथ्म का उपयोग कर सकते हैं और फिर संख्याओं पर पुनरावृति कर सकते हैं और उस संख्या से बड़ी संख्याओं का पता लगा सकते हैं।

array={...the billion numbers...} 
result[100];

pivot=QuickSelect(array,billion-101);//O(N)

for(i=0;i<billion;i++)//O(N)
   if(array[i]>=pivot)
      result.add(array[i]);

यह एल्गोरिथम समय है: 2 XO (N) = O (N) (औसत स्थिति प्रदर्शन)

थॉमस जुंगब्लेट सुझाव जैसा दूसरा विकल्प है:

हेप बिल्डिंग का उपयोग करें मैक्स हीप ओ (एन) को ले जाएगा, फिर शीर्ष 100 अधिकतम संख्या हीप के शीर्ष में होगी, आपको बस इतना करना है कि उन्हें ढेर से बाहर निकालना है (100 एक्सओ (लॉग) (एन))।

यह एल्गोरिथम समय है: O (N) + 100 XO (लॉग (N)) = O (N)


8
आप पूरी सूची के माध्यम से तीन बार काम कर रहे हैं। 1 जैव। पूर्णांक लगभग 4 जीबी हैं, यदि आप उन्हें मेमोरी में फिट नहीं कर सकते हैं तो आप क्या करेंगे? quickselect इस मामले में सबसे खराब संभव विकल्प है। एक बार में बदलना और शीर्ष 100 वस्तुओं का ढेर रखना IMHO O (n) में सबसे अच्छा प्रदर्शन करने वाला समाधान है (ध्यान दें कि आप ढेर आवेषण के O (लॉग एन) को काट सकते हैं क्योंकि ढेर में n 100 = स्थिर = बहुत छोटा है )।
थॉमस जुंगब्लूट

3
हालांकि यह अभी भी है O(N), दो क्विकसेलेक्ट्स और एक अन्य लीनियर स्कैन करना जरूरत से ज्यादा ओवरहेड है।
केविन

यह PSEUDO कोड है, यहां सभी समाधानों में अधिक समय लगेगा (O (NLOG (N) या 100 * O (N))
One Man Crew

1
100*O(N)(यदि मान्य सिंटैक्स है) = O(100*N)= O(N)(वैसे 100, चर हो सकता है यदि हां, तो यह नहीं सख्ती से सच है)। ओह, और क्विकसेलेट में O (N ^ 2) (ouch) का सबसे खराब प्रदर्शन है । और अगर यह मेमोरी में फिट नहीं होता है, तो आप डिस्क से डेटा को दो बार फिर से लोड कर रहे होंगे, जो एक बार से बहुत खराब है (यह अड़चन है)।
बर्नहार्ड बार्कर

ऐसा मुद्दा है कि यह चलने का समय है, और सबसे खराब स्थिति नहीं है, लेकिन एक अच्छी धुरी चयन रणनीति का उपयोग करके (जैसे यादृच्छिक पर 21 तत्वों को चुनें, और उन 21 के मध्य को धुरी के रूप में चुनें), फिर तुलनाओं की संख्या हो सकती है मनमाने ढंग से छोटे निरंतर सी के लिए अधिकतम (2 + c) n पर होने की उच्च संभावना के साथ गारंटी।
वन मैन क्रू

10

यद्यपि अन्य क्विकसेलेक्ट सॉल्यूशन को डाउनवोट किया गया है, लेकिन तथ्य यह है कि क्विकसेकेशन आकार 100 की कतार का उपयोग करने की तुलना में समाधान को तेजी से ढूंढेगा। क्विकसेलेप में तुलना के संदर्भ में 2n + o (n) का अपेक्षित रनिंग टाइम है। एक बहुत ही सरल कार्यान्वयन होगा

array = input array of length n
r = Quickselect(array,n-100)
result = array of length 100
for(i = 1 to n)
  if(array[i]>r)
     add array[i] to result

यह औसतन 3n + o (n) तुलना करेगा। इसके अलावा, इस तथ्य का उपयोग करके इसे अधिक कुशल बनाया जा सकता है कि क्विकसेले 100 सही-सबसे अधिक स्थानों में सरणी में सबसे बड़ी 100 वस्तुओं को छोड़ देगा। तो वास्तव में, चलने का समय 2n + o (n) में सुधार किया जा सकता है।

ऐसा मुद्दा है कि यह चलने का समय है, और सबसे खराब स्थिति नहीं है, लेकिन एक अच्छी धुरी चयन रणनीति का उपयोग करके (जैसे यादृच्छिक पर 21 तत्वों को चुनें, और उन 21 के मध्य को धुरी के रूप में चुनें), फिर तुलनाओं की संख्या हो सकती है मनमाने ढंग से छोटे निरंतर सी के लिए अधिकतम (2 + c) n पर होने की उच्च संभावना के साथ गारंटी।

वास्तव में, यादृच्छिक रूप से एक अनुकूलित नमूना रणनीति (उदाहरण के लिए नमूना sqrt (n) तत्वों का उपयोग करके, और 99 वें प्रतिशताइल का चयन करें), चल रहे समय को मनमाने ढंग से छोटे c के लिए (1 + c) n + o (n) से कम किया जा सकता है। (यह मानते हुए कि K, चुने जाने वाले तत्वों की संख्या o (n) है)।

दूसरी ओर, आकार 100 की एक कतार का उपयोग करके ओ (लॉग (100) एन) तुलना की आवश्यकता होगी, और 100 का लॉग बेस 2 लगभग 6.6 के बराबर है।

यदि हम इस समस्या के बारे में सोचते हैं, तो आकार N की एक सरणी से सबसे बड़े K तत्वों को चुनने के अधिक सार अर्थ में, जहां K = o (N) लेकिन K और N दोनों अनंत में जाते हैं, तो क्विकलेक्शन संस्करण का रनिंग टाइम होगा O (N) और कतार संस्करण O (N लॉग K) होगा, इसलिए इस अर्थ में क्विक्लीमेंट भी विषम रूप से श्रेष्ठ है।

टिप्पणियों में, यह उल्लेख किया गया था कि कतार समाधान यादृच्छिक इनपुट पर अपेक्षित समय एन + के लॉग एन में चलेगा। बेशक, यादृच्छिक इनपुट धारणा कभी भी मान्य नहीं होती है जब तक कि यह प्रश्न स्पष्ट रूप से नहीं बताता है। एक यादृच्छिक क्रम में सरणी को पार करने के लिए कतार समाधान किया जा सकता है, लेकिन यह एक यादृच्छिक संख्या जनरेटर को एन कॉल की अतिरिक्त लागत के साथ-साथ या तो पूरे इनपुट सरणी को अनुमति देने या अन्यथा लंबाई के एक नए सरणी को आवंटित करने में सक्षम होगा जिसमें एन शामिल है। यादृच्छिक सूचकांक।

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


4
आपका अंतिम पैराग्राफ प्रमुख बिंदु है: एक अरब संख्याओं के साथ, यह सभी डेटा को मेमोरी में रखने या आसपास के तत्वों को स्वैप करने के लिए संभव नहीं है। (कम से कम यह है कि मैं इस समस्या की व्याख्या कैसे करूंगा, यह देखते हुए कि यह एक साक्षात्कार प्रश्न था।)
टेड हॉप

14
किसी भी एल्गोरिथम प्रश्न में, यदि डेटा पढ़ना एक समस्या है, तो इसे प्रश्न में उल्लेख किया जाना चाहिए। प्रश्न में कहा गया है कि "एक सरणी" दिया गया है "डिस्क पर एक सरणी दी गई है जो स्मृति में फिट नहीं होती है और वॉन न्यूमन मॉडल के अनुसार हेरफेर नहीं किया जा सकता है जो एल्गोरिदम के विश्लेषण में मानक है"। इन दिनों आप 8gigs के रैम के साथ एक लैपटॉप प्राप्त कर सकते हैं। मुझे यकीन नहीं है कि स्मृति में एक अरब संख्या रखने का विचार संभव नहीं है। अभी मेरे वर्कस्टेशन पर मेमोरी में कई बिलियन नंबर हैं।
mrip

FYI करें वर्स्ट-केस के रनटाइम का हे (n ^ 2) है (देखें en.wikipedia.org/wiki/Quickselect ), और यह इनपुट ऐरे में तत्वों के क्रम को भी संशोधित करता है। एक बहुत बड़े स्थिरांक ( en.wikipedia.org/wiki/Median_of_medians ) के साथ सबसे खराब स्थिति O (n) समाधान होना संभव है ।
अंक

क्विकसेक्ट का सबसे खराब मामला तेजी से घटित होने की संभावना नहीं है, जिसका अर्थ है कि व्यावहारिक उद्देश्यों के लिए यह अप्रासंगिक है। क्विक को संशोधित करना आसान है ताकि उच्च संभावना के साथ तुलनात्मक रूप से छोटे सी के लिए तुलना (2 + c) n + o (n) हो।
मृग

"तथ्य यह है कि क्विकसेलेक्शन आकार 100 की कतार का उपयोग करने की तुलना में तेजी से समाधान ढूंढेगा" - नोप। ढेर समाधान N + Klog (N) तुलना बनाम 2N औसत के लिए क्विकलेक्शन और 2.95 मेडियन ऑफ मेडियंस के लिए लेता है। यह स्पष्ट रूप से दिए गए लालकृष्ण लिए तेजी से होता है
नील जी

5

बिलियन के पहले 100 नंबर लें और उन्हें सॉर्ट करें। अब केवल बिल के माध्यम से पुनरावृति, यदि स्रोत संख्या 100 से छोटी है, तो क्रमबद्ध क्रम में डालें। आप जिस चीज के साथ समाप्त होते हैं, वह सेट के आकार पर O (n) के बहुत करीब है।


3
उफ़ मेरे स्वयं के मुकाबले अधिक विस्तृत जवाब नहीं देखा।
सैमुअल थर्स्टन

जब सूची भरती है तो पहले 500 या तो संख्याएँ लें और केवल छांटना (और कम 400 को बाहर फेंकना) करें। (और यह कहे बिना चला जाता है कि आप तब केवल सूची में जोड़ें यदि नया नंबर> चयनित 100 में सबसे कम है।)
Hot Licks

4

दो विकल्प:

(1) ढेर (प्राथमिकता क्यू)

100 के आकार के साथ एक मिनट-ढेर बनाए रखें। सरणी को पार करें। एक बार जब तत्व हीप में पहले तत्व से छोटा होता है, तो इसे प्रतिस्थापित करें।

InSERT ELEMENT INTO HEAP: O(log100)
compare the first element: O(1)
There are n elements in the array, so the total would be O(nlog100), which is O(n)

(२) नक्शा कम करने वाला मॉडल।

यह हडूप में शब्द गणना उदाहरण के समान है। मानचित्र कार्य: प्रत्येक तत्व की आवृत्ति या समय की गणना करें। कम करें: शीर्ष K तत्व प्राप्त करें।

आमतौर पर, मैं भर्तीकर्ता को दो उत्तर दूंगा। उन्हें जो अच्छा लगे वो दे दो। बेशक, मानचित्र कम करना कोडिंग श्रम-कुछ होगा क्योंकि आपको हर सटीक मापदंडों को जानना होगा। इसका अभ्यास करने में कोई बुराई नहीं है। शुभ लाभ।


MapReduce के लिए +1, मुझे विश्वास नहीं हो रहा है कि आप एक बिलियन नंबरों के लिए Hadoop का उल्लेख कर रहे थे। क्या होगा यदि साक्षात्कारकर्ता ने 1k बिलियन नंबर मांगे? आप मेरी राय में अधिक वोट के लायक हैं।
सिल्वीयू बर्किया

@ सिल्वु बुरसा बहुत बहुत धन्यवाद। मैं MapReduce को भी महत्व देता हूं। :)
क्रिस सु

हालांकि इस उदाहरण में 100 का आकार स्थिर है, आपको वास्तव में इसे एक अलग चर के लिए सामान्यीकृत करना चाहिए। क। चूंकि 100 1 बिलियन के बराबर है, इसलिए आप संख्याओं के बड़े सेट का आकार n का आकार चर क्यों दे रहे हैं, और संख्याओं के छोटे सेट के लिए नहीं? वास्तव में आपकी जटिलता O (nlogk) होनी चाहिए जो O (n) नहीं है।
टॉम हर्ड

1
लेकिन मेरी बात यह है कि यदि आप केवल प्रश्न का उत्तर दे रहे हैं, तो प्रश्न में 1 बिलियन भी निर्धारित है, इसलिए 1 बिलियन से n को सामान्य करें और 100 को k नहीं। आपके तर्क के बाद, जटिलता वास्तव में O (1) होनी चाहिए क्योंकि इस प्रश्न में 1 बिलियन और 100 दोनों निर्धारित हैं।
टॉम हर्ड

1
@TomHeard सब ठीक है। O (nlogk) केवल एक कारक है जो परिणामों को प्रभावित करेगा। इसका मतलब है, यदि n बड़ा और बड़ा हो रहा है, तो "परिणाम स्तर" में रैखिक रूप से वृद्धि होगी। या हम कह सकते हैं, यहां तक ​​कि ट्रिलियन नंबर दिए गए, मैं अभी भी 100 सबसे बड़ी संख्या प्राप्त कर सकता हूं। हालाँकि, आप यह नहीं कह सकते हैं: n बढ़ने के साथ, k बढ़ रहा है जिससे k परिणाम को प्रभावित करेगा। इसलिए मैं O (nlogk) का उपयोग करता हूं, लेकिन O (nlogn) का नहीं
क्रिस Su

4

एक बहुत ही आसान समाधान 100 बार सरणी के माध्यम से पुनरावृत्त करना होगा। कौन सा है O(n)

हर बार जब आप सबसे बड़ी संख्या निकालते हैं (और इसके मूल्य को न्यूनतम मान में बदल देते हैं, ताकि आप इसे अगले पुनरावृत्ति में न देखें, या पिछले उत्तरों के अनुक्रमितों पर नज़र रखें) एक ही संख्या के कई))। 100 पुनरावृत्तियों के बाद, आपके पास 100 सबसे बड़ी संख्याएं हैं।


1
दो नुकसान - (1) आप प्रक्रिया में इनपुट को नष्ट कर रहे हैं - यह अधिमानतः बचा है। (2) आप कई बार ऐरे से गुजर रहे हैं - अगर एरे डिस्क पर स्टोर है और मेमोरी में फिट नहीं हो सकता है, तो यह स्वीकृत उत्तर की तुलना में लगभग 100 गुना धीमा हो सकता है। (हां, वे दोनों ओ (एन) हैं, लेकिन अभी भी)
बर्नहार्ड बार्कर

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

O (n) समाधान का एक शानदार उदाहरण जो O (n log n) की तुलना में बहुत धीमा है। log2 (1 बिलियन) केवल 30 है ...
gnasher729

@ gnasher729 O (n log n) में स्थिरांक कितना बड़ा है?
चमत्कार 173

1

@Ron टेलर के जवाब से प्रेरित होकर, आप क्या चाहते हैं, यह करने के लिए एक नंगे सी कार्यक्रम है।

#include <stdlib.h>
#include <stdio.h>

#define TOTAL_NUMBERS 1000000000
#define N_TOP_NUMBERS 100

int 
compare_function(const void *first, const void *second)
{
    int a = *((int *) first);
    int b = *((int *) second);
    if (a > b){
        return 1;
    }
    if (a < b){
        return -1;
    }
    return 0;
}

int 
main(int argc, char ** argv)
{
    if(argc != 2){
        printf("please supply a path to a binary file containing 1000000000"
               "integers of this machine's wordlength and endianness\n");
        exit(1);
    }
    FILE * f = fopen(argv[1], "r");
    if(!f){
        exit(1);
    }
    int top100[N_TOP_NUMBERS] = {0};
    int sorts = 0;
    for (int i = 0; i < TOTAL_NUMBERS; i++){
        int number;
        int ok;
        ok = fread(&number, sizeof(int), 1, f);
        if(!ok){
            printf("not enough numbers!\n");
            break;
        }
        if(number > top100[0]){
            sorts++;
            top100[0] = number;
            qsort(top100, N_TOP_NUMBERS, sizeof(int), compare_function);
        }

    }
    printf("%d sorts made\n"
    "the top 100 integers in %s are:\n",
    sorts, argv[1] );
    for (int i = 0; i < N_TOP_NUMBERS; i++){
        printf("%d\n", top100[i]);
    }
    fclose(f);
    exit(0);
}

मेरी मशीन पर (तेजी से एसएसडी के साथ कोर i3) यह 25 सेकंड, और 1724 तरह लेता है। मैंने dd if=/dev/urandom/ count=1000000000 bs=1इस रन के लिए एक बाइनरी फाइल जेनरेट की।

जाहिर है, डिस्क से एक समय में केवल 4 बाइट्स पढ़ने के साथ प्रदर्शन के मुद्दे हैं, लेकिन यह उदाहरण के लिए है। प्लस साइड पर, बहुत कम मेमोरी की आवश्यकता होती है।


1

सबसे सरल उपाय यह है कि अरब संख्याओं को बड़े सरणी में स्कैन किया जाए और बिना किसी छँटाई के छोटे सरणी बफर में अब तक पाए गए 100 सबसे बड़े मूल्यों को पकड़ें और इस बफर के सबसे छोटे मूल्य को याद रखें। पहले मैंने सोचा था कि यह विधि fordprefect द्वारा प्रस्तावित की गई थी, लेकिन एक टिप्पणी में उन्होंने कहा कि उन्होंने 100 नंबर डेटा संरचना को एक ढेर के रूप में कार्यान्वित किया। जब भी कोई नया नंबर पाया जाता है जो बड़ा होता है तो बफर में न्यूनतम पाया गया नया मान समाप्त हो जाता है और बफर को वर्तमान न्यूनतम के लिए फिर से खोजा जाता है। यदि बिलियन नंबर सरणी में संख्याओं को बेतरतीब ढंग से वितरित किया जाता है, तो बड़े सरणी से मूल्य को छोटे सरणी के न्यूनतम की तुलना में छोड़ दिया जाता है। केवल संख्या के बहुत छोटे अंश के लिए मान को छोटे सरणी में डाला जाना चाहिए। तो छोटी संख्या को धारण करने वाले डेटा संरचना में हेरफेर करने के अंतर को उपेक्षित किया जा सकता है। तत्वों की एक छोटी संख्या के लिए यह निर्धारित करना कठिन है कि क्या प्राथमिकता कतार का उपयोग वास्तव में मेरे भोले दृष्टिकोण का उपयोग करने से तेज है।

मैं 10 ^ 9 तत्व सरणी स्कैन किए जाने पर छोटे 100 तत्व सरणी बफर में आवेषण की संख्या का अनुमान लगाना चाहता हूं। कार्यक्रम इस बड़े सरणी के पहले 1000 तत्वों को स्कैन करता है और बफर में अधिकांश 1000 तत्वों को सम्मिलित करना होता है। बफर में स्कैन किए गए 1000 तत्वों में से 100 तत्व हैं, जो स्कैन किए गए तत्व का 0.1 है। तो हम मानते हैं कि बड़े सरणी से एक मान बफर के वर्तमान न्यूनतम से बड़ा है इसकी संभावना लगभग 0.1 है ऐसे तत्व को बफर में डाला जाना है। अब कार्यक्रम बड़े सरणी से अगले 10 ^ 4 तत्वों को स्कैन करता है। क्योंकि हर बार नया तत्व डालने पर बफर की न्यूनतम वृद्धि होगी। हमने अनुमान लगाया कि हमारे वर्तमान न्यूनतम से बड़े तत्वों का अनुपात लगभग 0.1 है और इसलिए डालने के लिए 0.1 * 10 ^ 4 = 1000 तत्व हैं। वास्तव में बफर में डाले गए तत्वों की अपेक्षित संख्या छोटी होगी। इस 10 ^ के स्कैन के बाद बफर में संख्याओं के 4 तत्व अंश अब तक स्कैन किए गए तत्वों में से लगभग 0.01 होंगे। इसलिए अगली 10 ^ 5 संख्याओं को स्कैन करते समय हम मान लेते हैं कि बफर में 0.01 * 10 ^ 5 = 1000 से अधिक नहीं डाला जाएगा। इस तर्क को जारी रखते हुए हमने 1000 + 10 ^ 4 + 10 ^ 5 + ... + 10 ^ 9 ~ 10 ^ 9 बड़े सरणी के तत्वों को स्कैन करने के बाद लगभग 7000 मान डाले हैं। इसलिए जब यादृच्छिक आकार के 10 ^ 9 तत्वों के साथ एक सरणी को स्कैन करते हुए हम बफर में 10 ^ 4 (= 7000 गोल ऊपर) आवेषण से अधिक नहीं होने की उम्मीद करते हैं। बफर में प्रत्येक प्रविष्टि के बाद नया न्यूनतम पाया जाना चाहिए। यदि बफ़र एक साधारण सरणी है तो हमें नया न्यूनतम खोजने के लिए 100 तुलना की आवश्यकता है। यदि बफर एक अन्य डेटा संरचना है (एक ढेर की तरह) तो हमें न्यूनतम खोजने के लिए कम से कम 1 तुलना की आवश्यकता है। बड़े सरणी के तत्वों की तुलना करने के लिए हमें 10 ^ 9 तुलनाओं की आवश्यकता होती है। इसलिए हम सभी को 10 ^ 9 + 100 * 10 ^ 4 = 1.001 * 10 ^ 9 तुलना की जरूरत है जब बफर के रूप में एक सरणी का उपयोग करते समय और कम से कम 1.000 * 10 ^ 9 तुलना किसी अन्य प्रकार की डेटा संरचना का उपयोग करते समय (एक ढेर की तरह) । तो एक ढेर का उपयोग केवल 0.1% का लाभ लाता है यदि प्रदर्शन तुलना की संख्या से निर्धारित होता है। लेकिन 100 तत्व के ढेर में एक तत्व डालने और 100 तत्व सरणी में एक तत्व को बदलने और इसके नए न्यूनतम खोजने के बीच निष्पादन समय में क्या अंतर है? किसी अन्य प्रकार की डेटा संरचना (जैसे ढेर) का उपयोग करते समय 000 * 10 ^ 9 तुलना। तो एक ढेर का उपयोग केवल 0.1% का लाभ लाता है यदि प्रदर्शन तुलना की संख्या से निर्धारित होता है। लेकिन 100 तत्व के ढेर में एक तत्व डालने और 100 तत्व सरणी में एक तत्व को बदलने और इसके नए न्यूनतम खोजने के बीच निष्पादन समय में क्या अंतर है? किसी अन्य प्रकार की डेटा संरचना (जैसे ढेर) का उपयोग करते समय 000 * 10 ^ 9 तुलना। तो एक ढेर का उपयोग केवल 0.1% का लाभ लाता है यदि प्रदर्शन तुलना की संख्या से निर्धारित होता है। लेकिन 100 तत्व के ढेर में एक तत्व डालने और 100 तत्व सरणी में एक तत्व को बदलने और इसके नए न्यूनतम खोजने के बीच निष्पादन समय में क्या अंतर है?

  • सैद्धांतिक स्तर पर: एक ढेर में डालने के लिए कितनी तुलनाओं की आवश्यकता होती है। मुझे पता है कि यह ओ (लॉग (एन)) है लेकिन स्थिर कारक कितना बड़ा है? मैं

  • मशीन स्तर पर: एक ढेर में निष्पादन और एक सरणी में रैखिक खोज के कैशिंग और शाखा भविष्यवाणी का प्रभाव क्या है।

  • कार्यान्वयन स्तर पर: एक पुस्तकालय या एक कंपाइलर द्वारा आपूर्ति की गई ढेर डेटा संरचना में क्या अतिरिक्त लागत छिपी हुई है?

मुझे लगता है कि ये कुछ ऐसे प्रश्न हैं जिनका उत्तर देने से पहले किसी को 100 तत्व हीप या 100 तत्व सरणी के प्रदर्शन के बीच वास्तविक अंतर का अनुमान लगाने की कोशिश की जा सकती है। तो यह एक प्रयोग करने और वास्तविक प्रदर्शन को मापने के लिए समझ में आता है।


1
यही एक ढेर है।
नील जी

@ नील जी: क्या "वह"?
चमत्कार 173

1
ढेर के शीर्ष ढेर में न्यूनतम तत्व है, और नए तत्वों को एक तुलना के साथ खारिज कर दिया जाता है।
नील जी

1
मैं समझता हूं कि आप क्या कह रहे हैं, लेकिन अगर आप तुलनात्मक संख्या के बजाय विषम संख्याओं की पूर्ण संख्या से जाते हैं, तो सरणी अभी भी बहुत धीमी है क्योंकि "नए तत्व को सम्मिलित करने, पुराने न्यूनतम को त्यागने और नए न्यूनतम खोजने का समय है" लगभग 7. के बजाय 100
नील जी

1
ठीक है, लेकिन आपका अनुमान बहुत गोल चक्कर वाला है। आप आवेषण की अपेक्षित संख्या की गणना सीधे k (डिगम्मा (n) - डिगामा (k)) से कर सकते हैं, जो klog (n) से कम है। किसी भी मामले में, ढेर और सरणी समाधान दोनों एक तत्व को छोड़ने के लिए केवल एक तुलना खर्च करते हैं। एकमात्र अंतर यह है कि एक सम्मिलित तत्व के लिए तुलना की संख्या ढेर के लिए आपके समाधान बनाम 14 के लिए 100 है (हालांकि औसत मामला शायद बहुत कम है।)
नील जी

1
 Although in this question we should search for top 100 numbers, I will 
 generalize things and write x. Still, I will treat x as constant value.

N से एल्गोरिथ्म सबसे बड़ा x तत्व:

मैं रिटर्न वैल्यू LIST कहूंगा । यह x तत्वों का एक सेट है (मेरी राय में जो लिस्ट से जुड़ा होना चाहिए)

  • पहले एक्स तत्वों को पूल से लिया जाता है "जैसा कि वे आते हैं" और एलआईएसटी में सॉर्ट किया गया है (यह निरंतर समय में किया जाता है क्योंकि एक्स को स्थिर माना जाता है - ओ (एक्स लॉग (एक्स)) समय)
  • अगले आने वाले प्रत्येक तत्व के लिए हम जाँचते हैं कि क्या यह लिस्ट में सबसे छोटे तत्व से बड़ा है और यदि हम सबसे छोटे से बाहर हैं और वर्तमान तत्व को लिस्ट में डालें। चूंकि यह आदेश दिया गया सूची है इसलिए प्रत्येक तत्व को लघुगणक समय (बाइनरी खोज) में अपनी जगह मिलनी चाहिए और चूंकि यह आदेश दिया जाता है सूची प्रविष्टि कोई समस्या नहीं है। प्रत्येक चरण निरंतर समय (O (लॉग (x)) समय) में भी किया जाता है।

तो, सबसे खराब स्थिति क्या है?

x लॉग (x) + (nx) (लॉग (x) +1) = nlog (x) + n - x

तो यह ओ (एन) सबसे खराब स्थिति के लिए समय है। +1, जाँच कर रहा है कि संख्या LIST में सबसे छोटी संख्या से अधिक है या नहीं। औसत मामले के लिए अपेक्षित समय उन n तत्वों के गणितीय वितरण पर निर्भर करेगा।

संभव सुधार

यह एल्गोरिदम सबसे खराब स्थिति के लिए थोड़ा सुधारा जा सकता है लेकिन IMHO (मैं इस दावे को साबित नहीं कर सकता) जो औसत व्यवहार को नीचा दिखाएगा। विषम व्यवहार समान होगा।

इस एल्गोरिथ्म में सुधार यह होगा कि हम जांच नहीं करेंगे कि तत्व सबसे छोटे से अधिक है या नहीं। प्रत्येक तत्व के लिए हम इसे सम्मिलित करने का प्रयास करेंगे और यदि यह छोटे से छोटा है तो हम इसकी अवहेलना करेंगे। हालाँकि यह बात बहुत ही अटपटी लगती है कि अगर हमारे पास केवल सबसे खराब स्थिति है तो हम क्या करेंगे

x लॉग (x) + (nx) लॉग (x) = nlog (x)

संचालन।

इस उपयोग के मामले में मुझे और सुधार नहीं दिख रहा है। फिर भी आपको अपने आप से पूछना चाहिए - क्या होगा यदि मुझे लॉग (एन) से अधिक बार और विभिन्न एक्स-एस के लिए यह करना है? जाहिर है हम उस सरणी को O (n log (n)) में क्रमबद्ध करेंगे और जब भी हमें उनकी आवश्यकता होगी, हमारा x तत्व ले लेंगे।


1

इस सवाल का जवाब एन लॉग (100) जटिलता (एन लॉग एन के बजाय) सी ++ कोड की सिर्फ एक पंक्ति के साथ दिया जाएगा।

 std::vector<int> myvector = ...; // Define your 1 billion numbers. 
                                 // Assumed integer just for concreteness 
 std::partial_sort (myvector.begin(), myvector.begin()+100, myvector.end());

अंतिम उत्तर एक वेक्टर होगा जहां पहले 100 तत्वों की गारंटी दी जाती है कि आप 100 सबसे बड़ी संख्या में हैं, जबकि शेष तत्व अनियंत्रित हैं

C ++ STL (मानक पुस्तकालय) इस तरह की समस्याओं के लिए काफी उपयोगी है।

नोट: मैं यह नहीं कह रहा हूं कि यह इष्टतम समाधान है, लेकिन इसने आपके साक्षात्कार को बचाया होगा।


1

सरल समाधान एक प्राथमिकता कतार का उपयोग करना होगा, कतार में पहले 100 संख्याओं को जोड़ना और कतार में सबसे छोटी संख्या का ट्रैक रखना, फिर अन्य अरब संख्याओं के माध्यम से पुनरावृत्ति करना, और हर बार हम एक को खोजते हैं जो सबसे बड़ी संख्या से बड़ा है प्राथमिकता कतार में, हम सबसे छोटी संख्या को हटाते हैं, नया नंबर जोड़ते हैं, और फिर से कतार में सबसे छोटी संख्या का ट्रैक रखते हैं।

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

तो हम पहले सरणी से 100,000 यादृच्छिक संख्या कहते हैं । रैंडम एक्सेस से बचने के लिए जो धीमा हो सकता है, हम कहते हैं कि 250 लगातार संख्याओं के 400 यादृच्छिक समूह। उस यादृच्छिक चयन के साथ, हम यह सुनिश्चित कर सकते हैं कि शेष संख्याओं में से बहुत कम शीर्ष सौ में हैं, इसलिए निष्पादन का समय एक साधारण लूप के करीब होगा जो कि एक अरब संख्या की तुलना में कुछ अधिकतम मूल्य है।


1

एक अरब संख्या में से शीर्ष 100 का पता लगाना 100 तत्वों के न्यूनतम-ढेर का उपयोग करके किया जाता है ।

पहले 100 नंबरों के साथ सबसे पहले प्राइम-हीप हुआ। मिन-हीप पहले 100 नंबर के सबसे छोटे को रूट (टॉप) पर स्टोर करेगा।

अब जैसा कि आप बाकी नंबरों के साथ जाते हैं, केवल उनकी तुलना रूट (100 में सबसे छोटी) से करते हैं।

यदि नया नंबर सामने आया है, तो वह मिन-हीप की जड़ से बड़ा है, उस नंबर को रूट से बदलें अन्यथा इसे अनदेखा करें।

न्यूनतम-हीप में नए नंबर की प्रविष्टि के हिस्से के रूप में हीप में सबसे छोटी संख्या शीर्ष (रूट) पर आएगी।

एक बार जब हम सभी नंबरों से गुजर चुके होते हैं तो हमारे पास मिन-हीप में सबसे बड़े 100 नंबर होंगे।


0

अगर किसी को दिलचस्पी है, तो मैंने पायथन में एक सरल समाधान लिखा है। यह bisectमॉड्यूल और एक अस्थायी वापसी सूची का उपयोग करता है जो इसे क्रमबद्ध रखता है। यह एक प्राथमिकता कतार कार्यान्वयन के समान है।

import bisect

def kLargest(A, k):
    '''returns list of k largest integers in A'''
    ret = []
    for i, a in enumerate(A):
        # For first k elements, simply construct sorted temp list
        # It is treated similarly to a priority queue
        if i < k:
            bisect.insort(ret, a) # properly inserts a into sorted list ret
        # Iterate over rest of array
        # Replace and update return array when more optimal element is found
        else:
            if a > ret[0]:
                del ret[0] # pop min element off queue
                bisect.insort(ret, a) # properly inserts a into sorted list ret
    return ret

100,000,000 तत्वों और सबसे खराब इनपुट के साथ उपयोग जो एक क्रमबद्ध सूची है:

>>> from so import kLargest
>>> kLargest(range(100000000), 100)
[99999900, 99999901, 99999902, 99999903, 99999904, 99999905, 99999906, 99999907,
 99999908, 99999909, 99999910, 99999911, 99999912, 99999913, 99999914, 99999915,
 99999916, 99999917, 99999918, 99999919, 99999920, 99999921, 99999922, 99999923,
 99999924, 99999925, 99999926, 99999927, 99999928, 99999929, 99999930, 99999931,
 99999932, 99999933, 99999934, 99999935, 99999936, 99999937, 99999938, 99999939,
 99999940, 99999941, 99999942, 99999943, 99999944, 99999945, 99999946, 99999947,
 99999948, 99999949, 99999950, 99999951, 99999952, 99999953, 99999954, 99999955,
 99999956, 99999957, 99999958, 99999959, 99999960, 99999961, 99999962, 99999963,
 99999964, 99999965, 99999966, 99999967, 99999968, 99999969, 99999970, 99999971,
 99999972, 99999973, 99999974, 99999975, 99999976, 99999977, 99999978, 99999979,
 99999980, 99999981, 99999982, 99999983, 99999984, 99999985, 99999986, 99999987,
 99999988, 99999989, 99999990, 99999991, 99999992, 99999993, 99999994, 99999995,
 99999996, 99999997, 99999998, 99999999]

100,000,000 तत्वों के लिए इसकी गणना करने में लगभग 40 सेकंड का समय लगता है इसलिए मुझे 1 बिलियन के लिए ऐसा करने में डर लगता है। हालांकि निष्पक्ष होने के लिए, मैं इसे सबसे खराब स्थिति इनपुट (विडंबना यह है कि पहले से ही हल किया गया है) खिला रहा था।


0

मुझे बहुत सारे ओ (एन) विचार-विमर्श दिखाई देते हैं, इसलिए मैंने सोचा अभ्यास के लिए कुछ अलग प्रस्तावित करता हूं।

क्या इन नंबरों की प्रकृति के बारे में कोई ज्ञात जानकारी है? यदि यह प्रकृति में यादृच्छिक है, तो आगे न जाएं और अन्य उत्तरों को देखें। इससे बेहतर परिणाम आपको नहीं मिलेंगे।

तथापि! देखें कि क्या है जो भी सूची-आबादी तंत्र ने एक विशेष क्रम में उस सूची को आबाद किया। क्या वे एक अच्छी तरह से परिभाषित पैटर्न में हैं जहां आप निश्चितता के साथ जान सकते हैं कि संख्याओं का सबसे बड़ा परिमाण सूची के एक निश्चित क्षेत्र में या एक निश्चित अंतराल पर मिलेगा? इसका एक पैटर्न हो सकता है। यदि ऐसा है, तो उदाहरण के लिए, यदि उन्हें बीच में विशेषता कूबड़ के साथ सामान्य वितरण के कुछ प्रकार में होने की गारंटी दी जाती है, तो हमेशा परिभाषित उपसमुच्चय के बीच ऊपर की ओर प्रवृत्ति दोहराई जाती है, डेटा के बीच में कुछ समय के लिए लंबे समय तक स्पाइक होता है। इनसाइडर ट्रेडिंग या उपकरण की विफलता की एक घटना की तरह सेट करें, या हो सकता है कि बस एक "स्पाइक" हो हर Nth संख्या के रूप में बलों के विश्लेषण में एक तबाही के बाद, आप रिकॉर्ड की संख्या को कम कर सकते हैं जिसे आपको महत्वपूर्ण रूप से जांचना होगा।

वैसे भी सोचा के लिए कुछ खाना है। शायद यह आपको भविष्य के साक्षात्कारकर्ताओं को एक विचारशील उत्तर देने में मदद करेगा। मुझे पता है कि मैं प्रभावित होऊंगा अगर कोई मुझसे इस तरह की समस्या के जवाब में ऐसा सवाल पूछे - यह मुझे बताएगा कि वे अनुकूलन के बारे में सोच रहे हैं। बस इस बात को पहचानें कि हमेशा अनुकूलन की संभावना नहीं हो सकती है।


0
Time ~ O(100 * N)
Space ~ O(100 + N)
  1. 100 खाली स्लॉट की एक खाली सूची बनाएं

  2. इनपुट-सूची में प्रत्येक संख्या के लिए:

    • यदि संख्या पहले वाले से छोटी है, तो स्किप करें

    • अन्यथा इसे इस संख्या से बदल दें

    • फिर, आसन्न स्वैप के माध्यम से संख्या को धक्का दें; यह अगले एक से छोटा है

  3. सूची वापस करें


नोट: यदि log(input-list.size) + c < 100, तो इष्टतम तरीका इनपुट-सूची को सॉर्ट करना है, तो पहले 100 आइटम विभाजित करें।


0

यह जटिलता हे (एन) है

पहले इस सरणी के पहले तत्व को एन मान के पहले तत्व के रूप में 100 इंच की एक सरणी बनाएँ, दूसरे तत्व के साथ वर्तमान तत्व के सूचकांक का ट्रैक रखें, इसे करेंटबिग

I मानों I को अलग करें

if N[i] > M[CurrentBig] {

M[CurrentBig]=N[i]; ( overwrite the current value with the newly found larger number)

CurrentBig++;      ( go to the next position in the M array)

CurrentBig %= 100; ( modulo arithmetic saves you from using lists/hashes etc.)

M[CurrentBig]=N[i];    ( pick up the current value again to use it for the next Iteration of the N array)

} 

जब किया जाता है, एम सरणी को CurrentBig से 100 बार मोडुलो 100 से प्रिंट करें :-) छात्र के लिए: सुनिश्चित करें कि कोड की अंतिम पंक्ति कोड से बाहर निकलने से पहले वैध डेटा को ट्रम्प नहीं करती है


0

एक और हे (एन) एल्गोरिथ्म -

एल्गोरिथ्म उन्मूलन द्वारा सबसे बड़ा 100 पाता है

उनके बाइनरी प्रतिनिधित्व में सभी मिलियन नंबरों पर विचार करें। सबसे महत्वपूर्ण बिट से शुरू करें। यदि एमएसबी 1 है तो ढूँढना एक उचित संख्या के साथ बूलियन ऑपरेशन गुणा द्वारा किया जा सकता है। यदि इन मिलियन में 100 1 से अधिक हैं, तो शून्य के साथ अन्य संख्याओं को समाप्त करें। अब शेष संख्या अगले सबसे महत्वपूर्ण बिट के साथ आगे बढ़ती है। उन्मूलन के बाद शेष संख्याओं की संख्या को ध्यान में रखें और जब तक यह संख्या 100 से अधिक न हो जाए।

प्रमुख बूलियन ऑपरेशन GPUs पर एक समान रूप से किया जा सकता है


0

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


0

आप इसे O(n)समय में कर सकते हैं । केवल सूची के माध्यम से पुनरावृत्ति करें और उस समूह में आपके द्वारा देखे गए 100 सबसे बड़े नंबरों और उस समूह में न्यूनतम मूल्य पर नज़र रखें। जब आप अपने दस में से सबसे छोटा एक नया नंबर पाते हैं, तो इसे बदल दें और अपने नए न्यूनतम मान को अपडेट करें (प्रत्येक बार ऐसा करने पर यह निर्धारित करने में 100 का निरंतर समय लग सकता है, लेकिन यह समग्र विश्लेषण को प्रभावित नहीं करता है )।


1
यह दृष्टिकोण इस प्रश्न के सबसे अधिक- और दूसरे-सबसे-उत्क्रमित दोनों के लिए लगभग समान है।
बर्नहार्ड बार्कर

0

एक अलग सूची का प्रबंधन करना अतिरिक्त काम है और आपको हर बार पूरी सूची में चीजों को स्थानांतरित करना होगा जब आप एक और प्रतिस्थापन पाएंगे। बस इसे qsort करें और शीर्ष 100 पर ले जाएं।


-1 एस्कॉर्ट ओ (एन लॉग एन) है जो ओपी ने ठीक किया है और सुधार करने के लिए कह रहा है। आपको एक अलग सूची का प्रबंधन करने की आवश्यकता नहीं है, केवल 100 नंबर की सूची। आपके सुझाव में मूल सूची को बदलने या उसे कॉपी करने का अवांछित दुष्प्रभाव भी है। यह 4GiB या स्मृति की, चला गया है।

0
  1. 100'th तत्व O (n) प्राप्त करने के लिए nth-element का उपयोग करें
  2. दूसरी बार Iterate करें लेकिन केवल एक बार और हर उस तत्व को आउटपुट करें जो इस विशिष्ट तत्व से अधिक है।

कृपया जासूसी करें। दूसरा चरण समानांतर में गणना करना आसान हो सकता है! और यह भी कुशलता से होगा जब आपको एक लाख सबसे बड़े तत्वों की आवश्यकता होगी।


0

यह Google या किसी अन्य उद्योग के दिग्गजों से एक सवाल है। फिर भी निम्नलिखित कोड आपके साक्षात्कारकर्ता द्वारा अपेक्षित सही उत्तर है। समय की लागत और स्थान की लागत इनपुट सरणी में अधिकतम संख्या पर निर्भर करती है। 32-बिट इंट सरणी इनपुट के लिए, अधिकतम स्थान लागत 4 * 125 मीटर बाइट्स है, समय लागत 5 * अरब है।

public class TopNumber {
    public static void main(String[] args) {
        final int input[] = {2389,8922,3382,6982,5231,8934
                            ,4322,7922,6892,5224,4829,3829
                            ,6892,6872,4682,6723,8923,3492};
        //One int(4 bytes) hold 32 = 2^5 value,
        //About 4 * 125M Bytes
        //int sort[] = new int[1 << (32 - 5)];
        //Allocate small array for local test
        int sort[] = new int[1000];
        //Set all bit to 0
        for(int index = 0; index < sort.length; index++){
            sort[index] = 0;
        }
        for(int number : input){
            sort[number >>> 5] |= (1 << (number % 32));
        }
        int topNum = 0;
        outer:
        for(int index = sort.length - 1; index >= 0; index--){
            if(0 != sort[index]){
                for(int bit = 31; bit >= 0; bit--){
                    if(0 != (sort[index] & (1 << bit))){
                        System.out.println((index << 5) + bit);
                        topNum++;
                        if(topNum >= 3){
                            break outer;
                        }
                    }
                }
            }
        }
    }
}

0

मैं अपने कोड किया, यकीन नहीं अगर इसकी "साक्षात्कारकर्ता" यह क्या लग रही है

private static final int MAX=100;
 PriorityQueue<Integer> queue = new PriorityQueue<>(MAX);
        queue.add(array[0]);
        for (int i=1;i<array.length;i++)
        {

            if(queue.peek()<array[i])
            {
                if(queue.size() >=MAX)
                {
                    queue.poll();
                }
                queue.add(array[i]);

            }

        }

0

संभव सुधार।

यदि फ़ाइल में 1 बिलियन नंबर है, तो इसे पढ़ना वास्तव में लंबा हो सकता है ...

इस कार्य को बेहतर बनाने के लिए आप कर सकते हैं:

  • फ़ाइल को n भागों में विभाजित करें, n थ्रेड बनाएँ, n थ्रेड्स फ़ाइल के अपने हिस्से में 100 सबसे बड़ी संख्याओं के लिए प्रत्येक को देखें (प्राथमिकता कतार का उपयोग करके), और अंत में सभी थ्रेड आउटपुट की 100 सबसे बड़ी संख्या प्राप्त करें।
  • इस तरह के कार्य को करने के लिए एक क्लस्टर का उपयोग करें, जैसे कि हूपअप। यहां आप फ़ाइल को और भी अधिक विभाजित कर सकते हैं और 1 बिलियन (या 10 ^ 12) नंबर फ़ाइल के लिए आउटपुट तेज कर सकते हैं।

0

पहले 1000 तत्व लें और उन्हें अधिकतम ढेर में जोड़ें। अब पहले अधिकतम 100 तत्वों को बाहर निकालें और इसे कहीं स्टोर करें। अब फ़ाइल से अगले 900 तत्वों को चुनें और उन्हें अंतिम 100 उच्चतम तत्व के साथ ढेर में जोड़ें।

ढेर से 100 तत्वों को उठाने और फ़ाइल से 900 तत्वों को जोड़ने की इस प्रक्रिया को दोहराते रहें।

100 तत्वों की अंतिम पिक हमें एक अरब संख्या से अधिकतम 100 तत्व देगी।


-1

समस्या: n वस्तुओं का सबसे बड़ा तत्व ज्ञात कीजिए जहाँ n >>> मी

सबसे सरल समाधान, जो हर किसी के लिए स्पष्ट होना चाहिए, बस बुलबुला सॉर्ट एल्गोरिथ्म के एम पास करना है।

फिर सरणी के अंतिम n तत्वों को प्रिंट करें।

इसके लिए किसी बाहरी डेटा संरचना की आवश्यकता नहीं है, और एक एल्गोरिथ्म का उपयोग किया जाता है जिसे हर कोई जानता है।

रनिंग टाइम का अनुमान O (m * n) है। अब तक का सबसे अच्छा उत्तर O (n log (m)) है, इसलिए यह समाधान छोटे m के लिए अधिक महंगा नहीं है।

मैं यह नहीं कह रहा हूं कि इसमें सुधार नहीं किया जा सकता, लेकिन यह अब तक का सबसे सरल उपाय है।


1
कोई बाहरी डेटा संरचना नहीं? क्या अरब नंबर सरणी के बारे में सॉर्ट करने के लिए? इस आकार की एक सरणी को भरने और स्थान को संग्रहीत करने के लिए दोनों समय में एक विशाल ओवरहेड है। क्या होगा यदि सभी "बड़ी" संख्याएं सरणी के गलत छोर पर थीं? आपको 100 बिलियन स्वैप के आदेश पर उन्हें स्थिति में "बुलबुला" करने की आवश्यकता होगी - एक और बड़ा उपरि ... अंत में, एम एन = 100 बिलियन बनाम एम लोग 2 (एन) = 6.64 बिलियन जो परिमाण अंतर के लगभग दो आदेश हैं। शायद इस पर फिर से विचार करें। सबसे बड़ी संख्याओं की डेटा संरचना को बनाए रखते हुए एक पास स्कैन इस दृष्टिकोण को पूरा करने के लिए महत्वपूर्ण है।
NealB
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.