ও (এন) এর দৈর্ঘ্যের এনআরআর্টেড অ্যারেতে কীথের বৃহত্তম উপাদানটি কীভাবে খুঁজে পাবেন?


220

আমি বিশ্বাস করি যে ও (এন) এর দৈর্ঘ্যের এনআরআর্টড অ্যারেতে kth বৃহত্তম উপাদানটি খুঁজে পাওয়ার কোনও উপায় আছে। অথবা সম্ভবত এটি "প্রত্যাশিত" ও (এন) বা অন্য কিছু। এটা আমরা কিভাবে করতে পারি?


49
যাইহোক, বেশিরভাগ এখানে বর্ণিত প্রতিটি অ্যালগরিদম যখন কে == এন হয় তখন ও (এন ^ 2) বা ও (এন লগ এন) এ পরিণত হয়। অর্থাৎ, আমি মনে করি না যে এর মধ্যে একটিরও কে এর সমস্ত মানের জন্য O (n)। আমি এটিকে নির্দেশ করার জন্য মোডেড হয়েছি তবে ভেবেছিলাম আপনার যাইহোক জানা উচিত।
কર્ક স্ট্রুয়েসার

19
নির্বাচনের অ্যালগরিদমগুলি কে এর কোনও নির্দিষ্ট মানের জন্য ও (এন) হতে পারে। অর্থাৎ, আপনার কে = 25 এর জন্য একটি নির্বাচন অ্যালগরিদম থাকতে পারে যা এন এর যে কোনও মানের জন্য ও (এন), এবং আপনি কে এর কোনও নির্দিষ্ট মানের জন্য এটি করতে পারেন যা n এর সাথে সম্পর্কিত নয়। যে ক্ষেত্রে আলগোরিদিম আর ও (এন) নেই সে ক্ষেত্রে যখন কে এর মান n এর মানের উপর কিছুটা নির্ভরশীলতা থাকে যেমন কে = এন বা কে = এন / 2। তবে এর অর্থ এই নয় যে আপনি যদি 25 আইটেমের তালিকায় k = 25 অ্যালগরিদম চালিয়ে যান তবে হঠাৎ এটি আর নেই (এন) কারণ ও-স্বীকৃতিটি অ্যালগরিদমের একটি বৈশিষ্ট্য বর্ণনা করে, একটি নির্দিষ্ট নয় এটি চালানো।
টাইলার ম্যাকহেনরি

1
দ্বিতীয় বৃহত্তম উপাদানটি খুঁজে পাওয়ার সাধারণ কেস হিসাবে আমাকে একটি অ্যামাজন সাক্ষাত্কারে এই প্রশ্ন জিজ্ঞাসা করা হয়েছিল। যেভাবে সাক্ষাত্কার সাক্ষাত্কারটির নেতৃত্ব দেয় আমি জিজ্ঞাসা করিনি যে আমি মূল অ্যারেটি (যেমন এটি বাছাই করা) নষ্ট করতে পারি, তাই আমি একটি জটিল সমাধান নিয়ে এসেছি।
সাম্বাত্যোন

4
এটি জন বেন্টলির প্রোগ্রামিং পার্লসের কলাম 11 (বাছাই করা) এর প্রশ্ন 9।
কিয়াং শো

3
@ কিরকস্ট্রাউজার: যদি কে == এন বা কে == এন -1 হয় তবে তা তুচ্ছ হয়ে যায়। আমরা একক ট্রভারসাল এ সর্বোচ্চ বা দ্বিতীয় সর্বোচ্চ পেতে পারি 2nd সুতরাং এখানে সরবরাহিত অ্যালগরিদমগুলি ব্যবহারিকভাবে কে এর মানগুলির জন্য ব্যবহার করা হবে যা {1,2, n-1, n belong এর সাথে সম্পর্কিত নয়
আদিত্য জোশি

উত্তর:


173

একে বলা হয় কে-থম অর্ডারের পরিসংখ্যান খুঁজে পাওয়া । খুব সাধারণ র্যান্ডমাইজড অ্যালগরিদম ( কুইকলেক্ট বলা হয় ) O(n)গড় সময় নেয়ায় , O(n^2)খারাপের সময় এবং একটি জটিল জটিল নন-র্যান্ডমাইজড অ্যালগরিদম (যাকে ইনট্রোসलेक्ट বলা হয় ) O(n)সবচেয়ে খারাপ সময় নেয়। উইকিপিডিয়ায় কিছু তথ্য আছে তবে এটি খুব ভাল নয়।

আপনার যা যা প্রয়োজন তা হ'ল এই পাওয়ারপয়েন্ট স্লাইডগুলিতেO(n)সর্বাধিক খারাপ অবস্থার অ্যালগোরিদম (অন্তঃসংশ্লিষ্ট) এর প্রাথমিক অ্যালগরিদমটি বের করতে :

Select(A,n,i):
    Divide input into ⌈n/5⌉ groups of size 5.

    /* Partition on median-of-medians */
    medians = array of each group’s median.
    pivot = Select(medians, ⌈n/5⌉, ⌈n/10⌉)
    Left Array L and Right Array G = partition(A, pivot)

    /* Find ith element in L, pivot, or G */
    k = |L| + 1
    If i = k, return pivot
    If i < k, return Select(L, k-1, i)
    If i > k, return Select(G, n-k, i-k)

এটি করমেন এট আল রচিত অ্যালগোরিদম বইয়ের ভূমিকাতে খুব সুন্দরভাবে বিস্তারিত।


6
স্লাইডগুলির জন্য আপনাকে ধন্যবাদ।
ক্ষিতিজ ব্যানার্জি

5
এটি 5 মাপের কাজ করতে হবে কেন? এটি 3 মাপের সাথে কেন কাজ করতে পারে না?
জোফ্রে বড়াথিয়ন

11
@ ইলাদভ স্লাইডগুলির লিঙ্কটি নষ্ট হয়েছে :(
মিশা মোরোশকো

7
@ ইলাদভ প্লিজ ভাঙা লিঙ্কটি ঠিক করুন।
maxx777

1
@ মিশা মোরোশকো লিঙ্কটি ঠিক হয়েছে
আলফাসিন

118

আপনি যদি সত্যিকারের O(n)অ্যালগরিদম চান O(kn)বা এর বিপরীতে বা এর মতো কিছু করেন তবে আপনার চটজলদি নির্বাচন করা উচিত (এটি মূলত কুইকোর্ট) যেখানে আপনি আগ্রহী নন এমন পার্টিশনটি ফেলে রেখেছেন)। রানটাইম বিশ্লেষণ সহ আমার প্রোফেসর দুর্দান্ত লেখার ব্যবস্থা করেছেন: ( রেফারেন্স )

কুইকসিলিট অ্যালগরিদমটি খুব দ্রুত কে-থতম ক্ষুদ্রতম উপাদানকে একটি অরসেটেড অ্যারের nউপাদানের সন্ধান করে। এটি একটি এলোমাইজড অ্যালগোরিদম , তাই আমরা চলমান সময়ের প্রত্যাশা সবচেয়ে খারাপ ক্ষেত্রে গণনা করি ।

এখানে এলগরিদম।

QuickSelect(A, k)
  let r be chosen uniformly at random in the range 1 to length(A)
  let pivot = A[r]
  let A1, A2 be new arrays
  # split into a pile A1 of small elements and A2 of big elements
  for i = 1 to n
    if A[i] < pivot then
      append A[i] to A1
    else if A[i] > pivot then
      append A[i] to A2
    else
      # do nothing
  end for
  if k <= length(A1):
    # it's in the pile of small elements
    return QuickSelect(A1, k)
  else if k > length(A) - length(A2)
    # it's in the pile of big elements
    return QuickSelect(A2, k - (length(A) - length(A2))
  else
    # it's equal to the pivot
    return pivot

এই অ্যালগরিদমের চলমান সময়টি কী? যদি শত্রুরা আমাদের জন্য মুদ্রা ফ্লিপ করে, আমরা দেখতে পাই যে পাইভট সর্বদা সর্ববৃহৎ উপাদান এবং kসর্বদা 1 থাকে, এর চলমান সময় দেয়

T(n) = Theta(n) + T(n-1) = Theta(n2)

তবে যদি পছন্দগুলি সত্যই এলোমেলো হয় তবে প্রত্যাশিত চলমান সময়টি দেওয়া হয়

T(n) <= Theta(n) + (1/n) ∑i=1 to nT(max(i, n-i-1))

যেখানে আমরা পুরোপুরি যুক্তিসঙ্গত অনুমান করি না যে পুনরাবৃত্তি সর্বদা A1বা এর বৃহত্তর স্থানে অবতরণ করে A2

T(n) <= anকিছু অনুমান করা যাক a। তারপরে আমরা পাই

T(n) 
 <= cn + (1/n) ∑i=1 to nT(max(i-1, n-i))
 = cn + (1/n) ∑i=1 to floor(n/2) T(n-i) + (1/n) ∑i=floor(n/2)+1 to n T(i)
 <= cn + 2 (1/n) ∑i=floor(n/2) to n T(i)
 <= cn + 2 (1/n) ∑i=floor(n/2) to n ai

এবং এখন কোনওভাবে cnবামদিকে শোষণের জন্য প্লাস চিহ্নের ডানদিকে ভয়াবহ যোগফলটি পেতে হবে । যদি আমরা এটি কেবল আবদ্ধ করি তবে আমরা মোটামুটিভাবে পাই । তবে এটি খুব বড় - অতিরিক্ত কোনও চাপ দেওয়ার মতো জায়গা নেই । সুতরাং গণিত সিরিজের সূত্রটি ব্যবহার করে যোগফলটি প্রসারিত করা যাক:2(1/n) ∑i=n/2 to n an2(1/n)(n/2)an = ancn

i=floor(n/2) to n i  
 = ∑i=1 to n i - ∑i=1 to floor(n/2) i  
 = n(n+1)/2 - floor(n/2)(floor(n/2)+1)/2  
 <= n2/2 - (n/4)2/2  
 = (15/32)n2

যেখানে আমরা কুশলীকে floor(n/2)আরও ক্লিনার (এবং আরও ছোট) এর সাথে প্রতিস্থাপন করতে "যথেষ্ট পরিমাণে বড়" হওয়ার সুযোগ নিই n/4। এখন আমরা সাথে চালিয়ে যেতে পারেন

cn + 2 (1/n) ∑i=floor(n/2) to n ai,
 <= cn + (2a/n) (15/32) n2
 = n (c + (15/16)a)
 <= an

প্রদত্ত a > 16c

এই দেয় T(n) = O(n)। এটা পরিষ্কার Omega(n), তাই আমরা পেয়েছি T(n) = Theta(n)


12
কুইক সিলেক্ট গড় ক্ষেত্রে কেবল ও (এন) হয়। মিডিয়ান অফ মিডিয়ান অ্যালগোরিদমকে সবচেয়ে খারাপ অবস্থায় ও (এন) সময়ে সমস্যার সমাধান করতে ব্যবহার করা যেতে পারে।
জন কুর্লক

এর অর্থ কী k > length(A) - length(A2)?
WoooHaaaa

এটি ও (এন) নয়, আপনি আবার ফাংশনটিকে পুনরাবৃত্ত, টি (এন) হিসাবে কল করছেন। পুনরাবৃত্তি ফাংশন টি (এন) এর মধ্যে ইতিমধ্যে সেখানে একটি ও (এন) রয়েছে, সুতরাং অবশ্যই চিন্তাভাবনা না করে সামগ্রিক জটিলতা ও (এন) এর চেয়ে বেশি হবে।
ব্যবহারকারী 1735921

3
@ ম্রোয়ে প্রদত্ত যে, আমরা পাইভট এবং এর চারপাশে Aবিভক্ত হয়েছি, আমরা জানি । সুতরাং, সমান , যা কোথাও ভিতরে থাকা যখন সত্য । A1A2length(A) == length(A1)+length(A2)+1k > length(A)-length(A2)k > length(A1)+1kA2
ফিলিপ গোনালভেস

@ ফিলিপগোনালভস, হ্যাঁ যদি পাইভটে কোনও সদৃশ উপাদান না থাকে। লেন (এ 1) + লেন (এ 2) + কে-সদৃশ = লেন (এ)
d1val

16

এর উপর একটি দ্রুত গুগল ('কেথ বৃহত্তম বৃহত্তম উপাদান অ্যারে') এটি ফিরিয়ে দিয়েছে: http://discuss.joelonsoftware.com/default.asp?interview.11.509587.17

"Make one pass through tracking the three largest values so far." 

(এটি বিশেষত 3 ডি বৃহত্তমের জন্য ছিল)

এবং এই উত্তর:

Build a heap/priority queue.  O(n)
Pop top element.  O(log n)
Pop top element.  O(log n)
Pop top element.  O(log n)

Total = O(n) + 3 O(log n) = O(n)

15
ভাল, এটি আসলে ও (এন) + ও (কে লগ এন) যা কে এর উল্লেখযোগ্য মানের জন্য হ্রাস করে না
জিমি

2
তবে দ্বিগুণ-সংযুক্ত তালিকার সন্নিবেশ বিন্দুটি হ'ল হে (কে)।
কার্ক স্ট্রুয়েজার

1
এবং যদি কে স্থির করা হয়, O (k) = O (1)
টাইলার ম্যাকহেঞ্জি

1
@ ওওয়ারেন: বিগ-ও আনুমানিক, তবে আপনি সর্বদা অতিরিক্ত-আনুমানিক। কুইকসোর্টটি আসলে ও (এন ^ 2), উদাহরণস্বরূপ, যেহেতু এটি সবচেয়ে খারাপ পরিস্থিতি। এটি হ'ল ও (এন + কে লগ এন)।
ক্লদিউ

1
আপনি K কে ধ্রুবক হিসাবে বিবেচনা করতে পারবেন না। এটা সম্ভব যে কে = এন যে ক্ষেত্রে সময়ের জটিলতা হ'ল (এনলগন)
সাব্বির

11

আপনি quicksort মত। এলোমেলোভাবে একটি উপাদান বাছুন এবং উচ্চতর বা নীচে সবকিছু নিক্ষেপ করুন এই মুহুর্তে আপনি জানতে পারবেন যে আপনি আসলে কোন উপাদানটি বেছে নিয়েছেন এবং যদি এটিই আপনি তৈরি করেন তবে এটি কোনও কাঠের উপাদান হয়ে থাকে, অন্যথায় আপনি বিন (উচ্চতর বা নিম্ন) দিয়ে পুনরাবৃত্তি করবেন যে কাঠের উপাদানটি পড়ে যাবে Stat পরিসংখ্যানগতভাবে বললে, সময় এটি n, O (n) দিয়ে কাঠের উপাদানটি বৃদ্ধি পেতে সন্ধান করে।


2
এটিই চটজলদি নির্বাচন, এফডাব্লুআইডাব্লু।
রজারডপ্যাক

6

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

আমি আপনার প্রশ্নের চিঠি উত্তর দিয়েছি :)


2
সব ক্ষেত্রেই সত্য নয়। আমি মিডিয়েন-অফ-মেডিয়ানগুলি প্রয়োগ করেছি এবং এটি NET এ বিল্ট-ইন বাছাইয়ের পদ্ধতির সাথে তুলনা করেছি এবং কাস্টম সলিউশনটি বিশালতার অর্ডারে সত্যিই দ্রুত চলেছে। এখন আসল প্রশ্ন হ'ল: প্রদত্ত পরিস্থিতিতে আপনার পক্ষে কি তা গুরুত্বপূর্ণ? কোনও লাইনারের তুলনায় কোডের 100 টি লাইন রচনা এবং ডিবাগিং কেবল তখনই প্রদান করা হয় যদি সেই কোডটি এতবার কার্যকর করা হয় যে ব্যবহারকারী চলমান সময়ের মধ্যে পার্থক্যটি লক্ষ্য করা শুরু করে এবং অপারেশনটি সম্পূর্ণ হওয়ার অপেক্ষায় অস্বস্তি বোধ করে।
জোড়ান হরভত

5

সি ++ স্ট্যান্ডার্ড লাইব্রেরিতে প্রায় ঠিক সেই ফাংশন কল রয়েছে nth_element, যদিও এটি আপনার ডেটা পরিবর্তন করে। এটি লিনিয়ার রান-টাইম, ও (এন) এর প্রত্যাশা করেছে এবং এটি একটি আংশিক বাছাইও করে।

const int N = ...;
double a[N];
// ... 
const int m = ...; // m < N
nth_element (a, a + m, a + N);
// a[m] contains the mth element in a

1
না, এটির একটি প্রত্যাশিত গড় ও (এন) রানটাইম রয়েছে। উদাহরণস্বরূপ, কুইকসোর্ট হ'ল O (nlogn) এর সবচেয়ে খারাপ ক্ষেত্রে ও (এন ^ 2) হয়। বাহ, সত্যিকারভাবে কিছু ভুল!
কर्क স্ট্রুজার

5
না, এই উত্তরটির সাথে আসলে ভুল কিছু নেই। এটি কাজ করে এবং সি ++ স্ট্যান্ডার্ডের জন্য একটি প্রত্যাশিত লিনিয়ার রান সময় প্রয়োজন।
ডেভিড নেহমে 0

আমাকে সাক্ষাত্কারে ও (কে) এর স্থান উপলব্ধতা এবং 'এন' খুব বিশাল বলে ধরে নিতে বলা হয়েছিল। আমি তাকে ও (এন) সমাধান বলতে পারিনি কারণ আমি ভেবেছিলাম nth_element এর জন্য জায়গার দরকার হবে o (n)। আমি কি ভুল? অন্তর্নিহিত অ্যালগরিদমটি nth_element এর জন্য ভিত্তিক কোয়ারকোর্ট নয়?
মনীষ বাফনা

4

যদিও ও (এন) জটিলতা সম্পর্কে খুব বেশি নিশ্চিত না তবে এটি ও (এন) এবং এনলগ (এন) এর মধ্যে থাকা নিশ্চিত হবে। এনলগ (এন) এর চেয়ে ও (এন) এর কাছাকাছি থাকা নিশ্চিত। জাভায় ফাংশন লেখা আছে

public int quickSelect(ArrayList<Integer>list, int nthSmallest){
    //Choose random number in range of 0 to array length
    Random random =  new Random();
    //This will give random number which is not greater than length - 1
    int pivotIndex = random.nextInt(list.size() - 1); 

    int pivot = list.get(pivotIndex);

    ArrayList<Integer> smallerNumberList = new ArrayList<Integer>();
    ArrayList<Integer> greaterNumberList = new ArrayList<Integer>();

    //Split list into two. 
    //Value smaller than pivot should go to smallerNumberList
    //Value greater than pivot should go to greaterNumberList
    //Do nothing for value which is equal to pivot
    for(int i=0; i<list.size(); i++){
        if(list.get(i)<pivot){
            smallerNumberList.add(list.get(i));
        }
        else if(list.get(i)>pivot){
            greaterNumberList.add(list.get(i));
        }
        else{
            //Do nothing
        }
    }

    //If smallerNumberList size is greater than nthSmallest value, nthSmallest number must be in this list 
    if(nthSmallest < smallerNumberList.size()){
        return quickSelect(smallerNumberList, nthSmallest);
    }
    //If nthSmallest is greater than [ list.size() - greaterNumberList.size() ], nthSmallest number must be in this list
    //The step is bit tricky. If confusing, please see the above loop once again for clarification.
    else if(nthSmallest > (list.size() - greaterNumberList.size())){
        //nthSmallest will have to be changed here. [ list.size() - greaterNumberList.size() ] elements are already in 
        //smallerNumberList
        nthSmallest = nthSmallest - (list.size() - greaterNumberList.size());
        return quickSelect(greaterNumberList,nthSmallest);
    }
    else{
        return pivot;
    }
}

ভাল কোডিং, +1। তবে অতিরিক্ত জায়গা ব্যবহার করার দরকার নেই।
হেনগামে

4

ডায়নামিক প্রোগ্রামিং, বিশেষত টুর্নামেন্টের পদ্ধতি ব্যবহার করে আমি এনআরএস্টেড উপাদানগুলিতে kth সর্বনিম্ন সন্ধানের প্রয়োগ করেছি। মৃত্যুদন্ড কার্যকর করার সময়টি হল (এন + ক্লোগ (এন))। ব্যবহৃত পদ্ধতিটি নির্বাচন অ্যালগরিদম সম্পর্কে উইকিপিডিয়া পৃষ্ঠায় অন্যতম পদ্ধতি হিসাবে তালিকাভুক্ত করা হয়েছে (উপরের পোস্টগুলির একটিতে নির্দেশিত হিসাবে)। আপনি অ্যালগরিদম সম্পর্কে পড়তে পারেন এবং আমার ব্লগ পৃষ্ঠায় Kth সর্বনিম্ন খুঁজে পেতে কোড (জাভা) খুঁজে পেতে পারেন । এছাড়াও যুক্তি তালিকার আংশিক অর্ডারিং করতে পারে - O (klog (n)) সময়ে প্রথম কে মিন (বা সর্বোচ্চ) ফিরে আসুন।

কোডটি ফলাফলের ন্যূনতম ন্যূনতম হলেও, টুর্নামেন্ট ট্রি তৈরির প্রাক-কাজকে উপেক্ষা করে ও (ক্লোগ (এন)) এ সর্বাধিক kth সন্ধান করার জন্য অনুরূপ যুক্তি ব্যবহার করা যেতে পারে।


3

আপনার দেখা সবচেয়ে বড় উপাদানগুলির ট্র্যাক রেখে আপনি এটি (ও + এন) = ও (এন) (ধ্রুবক কে জন্য) জন্য এবং স্পেসের জন্য ও (কে) এ করতে পারেন।

অ্যারের প্রতিটি উপাদানের জন্য আপনি কে বৃহত্তম বৃহত্তম তালিকাটি স্ক্যান করতে পারেন এবং সবচেয়ে বড়টি যদি ছোট উপাদানের সাথে নতুনকে প্রতিস্থাপন করতে পারেন।

ওয়ারেনের অগ্রাধিকারের হিপ সলিউশন যদিও কম।


3
এটিতে ও (n ^ 2) এর সবচেয়ে খারাপ পরিস্থিতি হবে যেখানে আপনাকে সবচেয়ে ছোট আইটেমটির জন্য জিজ্ঞাসা করা হয়েছে।
এলি

2
"ক্ষুদ্রতম আইটেম" এর অর্থ কে = এন, সুতরাং কে আর ধ্রুবক নয়।
টাইলার ম্যাকহেনরি

অথবা আপনি এ পর্যন্ত দেখা সবচেয়ে বড় কে'র একটি গাদা (বা বিপরীত apੇਰ, বা সুষম গাছ) রাখুন O(n log k)... এখনও বড় কে এর ক্ষেত্রে O (nlogn) তে অবনমিত হয়। আমি মনে করি এটি কে-এর ছোট মানগুলির জন্য ভাল কাজ করবে ... সম্ভবত এখানে বর্ণিত অন্যান্য অ্যালগোরিদমের তুলনায় দ্রুত [???]
রজারডপ্যাক

3

পাইথনে সেক্সি চটজলদি নির্বাচন

def quickselect(arr, k):
    '''
     k = 1 returns first element in ascending order.
     can be easily modified to return first element in descending order
    '''

    r = random.randrange(0, len(arr))

    a1 = [i for i in arr if i < arr[r]] '''partition'''
    a2 = [i for i in arr if i > arr[r]]

    if k <= len(a1):
        return quickselect(a1, k)
    elif k > len(arr)-len(a2):
        return quickselect(a2, k - (len(arr) - len(a2)))
    else:
        return arr[r]

চমৎকার সমাধান, ব্যতীত এটি একটি অরসোর্টড তালিকার মধ্যে kth ক্ষুদ্রতম উপাদানটি দেয়। তালিকার উপলব্ধিগুলিতে তুলনা অপারেটরগুলিকে বিপরীত করা, a1 = [i for i in arr if i > arr[r]]এবং a2 = [i for i in arr if i < arr[r]], কেথ বৃহত্তম বৃহত্তম উপাদানটি ফিরিয়ে দেবে ।
আড়ম্বর

একটি ছোট মাপদণ্ড থেকে, এমনকি বড় অ্যারেতেও, এই ম্যানুয়াল বাস্তবায়নটি ব্যবহার করার চেয়ে বাছাই করা ( তালিকার numpy.sortজন্য numpy arrayবা এর সাথে sorted) আরও দ্রুত is
নরীন

2

রৈখিক সময়ের মধ্যে অ্যারের মাঝারিটি সন্ধান করুন, তারপরে অ্যারিকে দুটি অংশে বিভক্ত করতে ঠিক একইভাবে পার্টিশন পদ্ধতিটি ব্যবহার করুন, মিডিয়ানের চেয়ে মিডিয়ানের চেয়ে কম (<) বামে এবং (>) মধ্যবর্তী থেকে ডানদিকে আরও বড় করুন , এটিও লাইন সময়ে করা যায়, এখন, অ্যারের সেই অংশে যান যেখানে kth উপাদান রয়েছে, এখন পুনরাবৃত্তি হয়ে যায়: টি (এন) = টি (এন / 2) + সিএন যা আমাকে ও (এন) ওভারাল দেয়।


মিডিয়ান খোঁজার দরকার নেই। মিডিয়ান ছাড়া আপনার পদ্ধতির এখনও ঠিক আছে।
হেনগামে

2
রৈখিক সময়ের মধ্যে আপনি কীভাবে মধ্যস্থতাকে খুঁজে পাবেন, আমি জিজ্ঞাসা করার সাহস করব? ... :)
রজারডপ্যাক

2

নিরবচ্ছিন্ন অ্যালগরিদম কিভাবে Kth উপাদান সন্ধানের জন্য অ্যালগরিদম কাজ করে তার বিস্তৃত ব্যাখ্যা সহ পুরো বাস্তবায়নের লিঙ্কটি। প্রাথমিক ধারণাটি কুইকসোর্টের মতো অ্যারে বিভক্ত করা। তবে চরম ক্ষেত্রে এড়াতে (উদাহরণস্বরূপ, যখন প্রতিটি পদক্ষেপে ক্ষুদ্রতম উপাদানকে পাইভট হিসাবে বেছে নেওয়া হয়, যাতে অ্যালগোরিদম ও (ন্যান into 2) চলমান সময়তে অবক্ষয় হয়), বিশেষ পিভট নির্বাচন প্রয়োগ করা হয়, যাকে মিডিয়েন-অফ-মেডিয়ান অ্যালগরিদম বলা হয়। পুরো সমাধানটি ও (এন) সময়ে সবচেয়ে খারাপ এবং গড় ক্ষেত্রে চলে।

এখানে সম্পূর্ণ নিবন্ধটির লিঙ্কটি রয়েছে (এটি Kth ক্ষুদ্রতম উপাদান সন্ধানের বিষয়ে , তবে Kth বৃহত্তম সন্ধানের জন্য নীতিটি একই ):

আনসোর্টেড অ্যারেতে কেথের ক্ষুদ্রতম এলিমেন্ট সন্ধান করা


2

এই কাগজ অনুসারে এন আইটেমগুলির তালিকায় Kth বৃহত্তম আইটেমটি সন্ধান করতে নিম্নলিখিত অ্যালগরিদমকে O(n)সবচেয়ে খারাপ ক্ষেত্রে সময় লাগবে ।

  1. প্রতিটি 5 টি উপাদানের এন / 5 তালিকায় অ্যারে ভাগ করুন।
  2. 5 টি উপাদানের প্রতিটি সাব অ্যারেতে মাঝারি সন্ধান করুন।
  3. পুনরাবৃত্তভাবে সমস্ত মিডিয়ানের মিডিয়ানকে এটিকে এম বলে call
  4. অ্যারেটিকে দুটি সাব অ্যারে বিভক্ত করুন প্রথম সাব-অ্যারে এম এর চেয়েও বড় উপাদান রয়েছে, যাক এই সাব-অ্যারেটি a1 হয়, অন্য সাব-অ্যারেতে এম এর পরে আরও ছোট উপাদান রয়েছে, এই উপ-অ্যারেটিকে A2 বলুন।
  5. যদি কে <= | এ 1 |, রিটার্ন নির্বাচন (এ 1, কে)।
  6. যদি k− 1 = | এ 1 |, এম ফেরত দিন
  7. যদি কে> | এ 1 | + 1, রিটার্ন নির্বাচন (a2, কে −a1 - 1)।

বিশ্লেষণ: মূল কাগজে যেমন পরামর্শ দেওয়া হয়েছে:

আমরা তালিকাটি দুটি ভাগে ভাগ করে (প্রথমার্ধ, যদি k <= n/2, এবং দ্বিতীয়ার্ধে অন্যথায়) ভাগ করি। এই অ্যালগরিদম cnতৃতীয় স্তরে c, cn/2পরবর্তী স্তরে (যেহেতু আমরা আকার n / 2 এর তালিকায় পুনরাবৃত্তি করি) কিছু ধ্রুবক জন্য পুনরাবৃত্তির প্রথম স্তরে সময় নেয় cn/4, এবং আরও অনেক কিছু। মোট সময় নেওয়া হয়েছে cn + cn/2 + cn/4 + .... = 2cn = o(n)

কেন পার্টিশনের আকার 5 নেওয়া হয় না 3?

মূল কাগজে যেমন উল্লেখ করা হয়েছে :

5 আশ্বাস 70 একটি খারাপ-কেস বিভক্ত তালিকায় ডিভাইডিং - 30. মধ্যমা অফ মধ্যমা তার চেয়ে অনেক বেশী মধ্যমা অন্তত অর্ধেক, অত এন / 5 ব্লক অর্ধেক অন্তত 3 উপাদান অন্তত আছে এবং এই একটি দেয় 3n/10বিভক্ত, যা মানে অন্য পার্টিশনটি 7n / 10 সবচেয়ে খারাপ ক্ষেত্রে worst যে দেয় T(n) = T(n/5)+T(7n/10)+O(n). Since n/5+7n/10 < 1, সবচেয়ে খারাপ সময় চলমান সময় O(n)

আমি এখন উপরোক্ত অ্যালগরিদমটি বাস্তবায়নের চেষ্টা করেছি:

public static int findKthLargestUsingMedian(Integer[] array, int k) {
        // Step 1: Divide the list into n/5 lists of 5 element each.
        int noOfRequiredLists = (int) Math.ceil(array.length / 5.0);
        // Step 2: Find pivotal element aka median of medians.
        int medianOfMedian =  findMedianOfMedians(array, noOfRequiredLists);
        //Now we need two lists split using medianOfMedian as pivot. All elements in list listOne will be grater than medianOfMedian and listTwo will have elements lesser than medianOfMedian.
        List<Integer> listWithGreaterNumbers = new ArrayList<>(); // elements greater than medianOfMedian
        List<Integer> listWithSmallerNumbers = new ArrayList<>(); // elements less than medianOfMedian
        for (Integer element : array) {
            if (element < medianOfMedian) {
                listWithSmallerNumbers.add(element);
            } else if (element > medianOfMedian) {
                listWithGreaterNumbers.add(element);
            }
        }
        // Next step.
        if (k <= listWithGreaterNumbers.size()) return findKthLargestUsingMedian((Integer[]) listWithGreaterNumbers.toArray(new Integer[listWithGreaterNumbers.size()]), k);
        else if ((k - 1) == listWithGreaterNumbers.size()) return medianOfMedian;
        else if (k > (listWithGreaterNumbers.size() + 1)) return findKthLargestUsingMedian((Integer[]) listWithSmallerNumbers.toArray(new Integer[listWithSmallerNumbers.size()]), k-listWithGreaterNumbers.size()-1);
        return -1;
    }

    public static int findMedianOfMedians(Integer[] mainList, int noOfRequiredLists) {
        int[] medians = new int[noOfRequiredLists];
        for (int count = 0; count < noOfRequiredLists; count++) {
            int startOfPartialArray = 5 * count;
            int endOfPartialArray = startOfPartialArray + 5;
            Integer[] partialArray = Arrays.copyOfRange((Integer[]) mainList, startOfPartialArray, endOfPartialArray);
            // Step 2: Find median of each of these sublists.
            int medianIndex = partialArray.length/2;
            medians[count] = partialArray[medianIndex];
        }
        // Step 3: Find median of the medians.
        return medians[medians.length / 2];
    }

কেবলমাত্র সমাপ্তির স্বার্থে, অন্য একটি অ্যালগরিদম অগ্রাধিকার সারি ব্যবহার করে এবং সময় নেয় O(nlogn)

public static int findKthLargestUsingPriorityQueue(Integer[] nums, int k) {
        int p = 0;
        int numElements = nums.length;
        // create priority queue where all the elements of nums will be stored
        PriorityQueue<Integer> pq = new PriorityQueue<Integer>();

        // place all the elements of the array to this priority queue
        for (int n : nums) {
            pq.add(n);
        }

        // extract the kth largest element
        while (numElements - k + 1 > 0) {
            p = pq.poll();
            k++;
        }

        return p;
    }

এই উভয় অ্যালগরিদম হিসাবে পরীক্ষা করা যেতে পারে:

public static void main(String[] args) throws IOException {
        Integer[] numbers = new Integer[]{2, 3, 5, 4, 1, 12, 11, 13, 16, 7, 8, 6, 10, 9, 17, 15, 19, 20, 18, 23, 21, 22, 25, 24, 14};
        System.out.println(findKthLargestUsingMedian(numbers, 8));
        System.out.println(findKthLargestUsingPriorityQueue(numbers, 8));
    }

প্রত্যাশিত আউটপুট হিসাবে: 18 18


@rogerdpack আমি অনুসরণ করা লিংকটি সরবরাহ করেছি।
akhil_mittal

2

কিভাবে এই ধরনের পদ্ধতির সম্পর্কে

একটি buffer of length kএবং একটি বজায় রাখুন tmp_max, tmp_max পেয়ে ও (কে) হয় এবং এন বার এমন কিছু করা হয়O(kn)

এখানে চিত্র বর্ণনা লিখুন

এটা ঠিক আছে নাকি আমি কিছু মিস করছি?

যদিও এটি দ্রুত পরিসংখ্যান পদ্ধতি এবং মিডিয়ান পরিসংখ্যান পদ্ধতির সবচেয়ে খারাপ অবস্থার গড় কেসটিকে হারাতে পারে না তবে এটি বোঝা এবং বাস্তবায়ন করা বেশ সহজ।


1
আমি এটি পছন্দ করি, বুঝতে সহজ। যদিও আপনি নির্দেশ করেছেন তেমন জটিলতা O (nk)।
হাজ্জাত

1

তালিকা মাধ্যমে পুনরাবৃত্তি। যদি বর্তমান মান সঞ্চিত বৃহত্তম মানের থেকে বড় হয় তবে এটিকে বৃহত্তম মান হিসাবে সংরক্ষণ করুন এবং 1-4 থেকে নীচে এবং 5 টি ড্রপকে তালিকা থেকে সরিয়ে দিন। যদি তা না হয় তবে এটি 2 নম্বরের সাথে তুলনা করুন এবং একই জিনিসটি করুন। পুনরাবৃত্তি করুন, সমস্ত 5 টি সঞ্চিত মানের তুলনায় এটি পরীক্ষা করা। এটি ও (এন) এ করা উচিত


যদি আপনি কোনও অ্যারে ব্যবহার করেন তবে "বাম্প" হ'ল (এন), অথবা আপনি যদি আরও ভাল কাঠামো ব্যবহার করেন তবে নীচে হে (লগ এন) (আমার মনে হয়)।
र्क স্ট্রুয়েজার 21

এটি ও (লগ কে) হওয়ার দরকার নেই - তালিকাটি যদি কোনও লিঙ্কযুক্ত তালিকা হয় তবে নতুন উপাদানটিকে শীর্ষে যুক্ত করা এবং শেষ উপাদানটি বাদ দেওয়া আরও ও (2) এর মতো
অ্যালনিটাক

टक्करটি অ্যারে-ব্যাকড তালিকার জন্য ও (কে) হবে, উপযুক্তভাবে সংযুক্ত তালিকার জন্য ও (1)। যে কোনও উপায়ে, এই ধরণের প্রশ্নটি সাধারণত এন এর তুলনায় এটি ন্যূনতম প্রভাব হিসাবে ধরে নেয় এবং এটি এন এর আরও কোনও কারণের পরিচয় দেয় না।
ববিনস

এটি ও (1) হ'ল যদি বাম্পটি রিং-বাফার ব্যবহার করে
Alnitak

1
যাইহোক, মন্তব্যটির অ্যালগরিদম অসম্পূর্ণ, এটি এন এর এমন একটি উপাদান বিবেচনা করতে ব্যর্থ হয়েছে যা নতুন (উদাঃ) দ্বিতীয় বৃহত্তম। সবচেয়ে খারাপ কেস আচরণ, যেখানে এন এর প্রতিটি উপাদানকে হাইস্কোর টেবিলের প্রত্যেকটির সাথে তুলনা করতে হবে, ও (না) - তবে এটি এখনও প্রশ্নের পরিপ্রেক্ষিতে সম্ভবত ও (এন) অর্থ means
ববিনস

1

আমি একটি উত্তর বলতে চাই

যদি আমরা প্রথম কে উপাদানগুলি গ্রহণ করি এবং কে মানগুলির একটি লিঙ্কযুক্ত তালিকায় তাদের সাজান

এখন প্রতিটি অন্যান্য মান এমনকি নিকৃষ্টতম ক্ষেত্রে এমনকি যদি আমরা বিশ্রামের এন কে মানগুলির জন্য সন্নিবেশ বাছাই করি এমনকি সবচেয়ে খারাপ ক্ষেত্রে তুলনামূলক সংখ্যার সংখ্যা কে * (এন কে) হবে এবং পূর্ববর্তী মানগুলি সাজানোর জন্য এটি কে * (কে- 1) সুতরাং এটি (এনকে-কে) যা ও (এন) এর বাইরে আসে

চিয়ার্স


1
বাছাইয়ের জন্য এনলগন সময় লাগে ... অ্যালগরিদমটি রৈখিক সময়ে চলতে হবে
মিঃ ডেটাবেস

1

মধ্যম - এর ব্যাখ্যা - এর মধ্যে- এর বৃহত্তম বৃহত্তম পূর্ণসংখ্যার খুঁজে বের করার জন্য মিডিয়ান অ্যালগরিদম এখানে পাওয়া যাবে: http://cs.indstate.edu/~spitla/preferencesation.pdf

সি ++ এ বাস্তবায়ন নীচে রয়েছে:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int findMedian(vector<int> vec){
//    Find median of a vector
    int median;
    size_t size = vec.size();
    median = vec[(size/2)];
    return median;
}

int findMedianOfMedians(vector<vector<int> > values){
    vector<int> medians;

    for (int i = 0; i < values.size(); i++) {
        int m = findMedian(values[i]);
        medians.push_back(m);
    }

    return findMedian(medians);
}

void selectionByMedianOfMedians(const vector<int> values, int k){
//    Divide the list into n/5 lists of 5 elements each
    vector<vector<int> > vec2D;

    int count = 0;
    while (count != values.size()) {
        int countRow = 0;
        vector<int> row;

        while ((countRow < 5) && (count < values.size())) {
            row.push_back(values[count]);
            count++;
            countRow++;
        }
        vec2D.push_back(row);
    }

    cout<<endl<<endl<<"Printing 2D vector : "<<endl;
    for (int i = 0; i < vec2D.size(); i++) {
        for (int j = 0; j < vec2D[i].size(); j++) {
            cout<<vec2D[i][j]<<" ";
        }
        cout<<endl;
    }
    cout<<endl;

//    Calculating a new pivot for making splits
    int m = findMedianOfMedians(vec2D);
    cout<<"Median of medians is : "<<m<<endl;

//    Partition the list into unique elements larger than 'm' (call this sublist L1) and
//    those smaller them 'm' (call this sublist L2)
    vector<int> L1, L2;

    for (int i = 0; i < vec2D.size(); i++) {
        for (int j = 0; j < vec2D[i].size(); j++) {
            if (vec2D[i][j] > m) {
                L1.push_back(vec2D[i][j]);
            }else if (vec2D[i][j] < m){
                L2.push_back(vec2D[i][j]);
            }
        }
    }

//    Checking the splits as per the new pivot 'm'
    cout<<endl<<"Printing L1 : "<<endl;
    for (int i = 0; i < L1.size(); i++) {
        cout<<L1[i]<<" ";
    }

    cout<<endl<<endl<<"Printing L2 : "<<endl;
    for (int i = 0; i < L2.size(); i++) {
        cout<<L2[i]<<" ";
    }

//    Recursive calls
    if ((k - 1) == L1.size()) {
        cout<<endl<<endl<<"Answer :"<<m;
    }else if (k <= L1.size()) {
        return selectionByMedianOfMedians(L1, k);
    }else if (k > (L1.size() + 1)){
        return selectionByMedianOfMedians(L2, k-((int)L1.size())-1);
    }

}

int main()
{
    int values[] = {2, 3, 5, 4, 1, 12, 11, 13, 16, 7, 8, 6, 10, 9, 17, 15, 19, 20, 18, 23, 21, 22, 25, 24, 14};

    vector<int> vec(values, values + 25);

    cout<<"The given array is : "<<endl;
    for (int i = 0; i < vec.size(); i++) {
        cout<<vec[i]<<" ";
    }

    selectionByMedianOfMedians(vec, 8);

    return 0;
}

এই সমাধান কাজ করে না। 5 টি এলিমেন্ট কেসের জন্য মিডিয়ানটি ফিরিয়ে দেওয়ার আগে আপনাকে অ্যারে বাছাই করতে হবে।
অগ্নিশম চট্টোপাধ্যায়

1

উইথের সিলেকশন অ্যালগরিদম এছাড়াও রয়েছে, যা কুইকসিলেক্টের চেয়ে সহজ বাস্তবায়ন করেছে। উইথের সিলেকশন অ্যালগরিদম কুইকসিলেক্টের চেয়ে ধীর, তবে কিছু উন্নতির সাথে এটি দ্রুত হয়।

আরো বিস্তারিত. ভ্লাদিমির জ্যাব্রোডস্কির মোডিফাইন্ড অপ্টিমাইজেশন এবং 3-পিভট সিডিয়াল মিডিয়েনটি অপ্টিমাইজেশন এবং অ্যালগরিদমের অংশীকরণের চূড়ান্ত পদক্ষেপের দিকে কিছুটা মনোযোগ দিয়ে আমি নিম্নলিখিত অ্যালগরিদম নিয়ে এসেছি (কল্পিতভাবে "লেফসিলিট" নাম দেওয়া হয়েছে):

#define F_SWAP(a,b) { float temp=(a);(a)=(b);(b)=temp; }

# Note: The code needs more than 2 elements to work
float lefselect(float a[], const int n, const int k) {
    int l=0, m = n-1, i=l, j=m;
    float x;

    while (l<m) {
        if( a[k] < a[i] ) F_SWAP(a[i],a[k]);
        if( a[j] < a[i] ) F_SWAP(a[i],a[j]);
        if( a[j] < a[k] ) F_SWAP(a[k],a[j]);

        x=a[k];
        while (j>k & i<k) {
            do i++; while (a[i]<x);
            do j--; while (a[j]>x);

            F_SWAP(a[i],a[j]);
        }
        i++; j--;

        if (j<k) {
            while (a[i]<x) i++;
            l=i; j=m;
        }
        if (k<i) {
            while (x<a[j]) j--;
            m=j; i=l;
        }
    }
    return a[k];
}

আমি এখানে যে বেঞ্চমার্কগুলিতে করেছি , লেফস্লিকট কুইকসিলেক্টের চেয়ে 20-30% দ্রুত।


1

হাস্কেল সমাধান:

kthElem index list = sort list !! index

withShape ~[]     []     = []
withShape ~(x:xs) (y:ys) = x : withShape xs ys

sort []     = []
sort (x:xs) = (sort ls `withShape` ls) ++ [x] ++ (sort rs `withShape` rs)
  where
   ls = filter (<  x)
   rs = filter (>= x)

এটি প্রকৃতরূপে গণনা না করে কোনও পার্টিশনের আকার আবিষ্কার করতে উইন্ড শেপ পদ্ধতিটি ব্যবহার করে মিডিয় সলিউশনের মধ্যস্থতাকে কার্যকর করে।


1

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

#include<iostream>
#include<climits>
#include<cstdlib>
using namespace std;

int randomPartition(int arr[], int l, int r);

// This function returns k'th smallest element in arr[l..r] using
// QuickSort based method.  ASSUMPTION: ALL ELEMENTS IN ARR[] ARE DISTINCT
int kthSmallest(int arr[], int l, int r, int k)
{
    // If k is smaller than number of elements in array
    if (k > 0 && k <= r - l + 1)
    {
        // Partition the array around a random element and
        // get position of pivot element in sorted array
        int pos = randomPartition(arr, l, r);

        // If position is same as k
        if (pos-l == k-1)
            return arr[pos];
        if (pos-l > k-1)  // If position is more, recur for left subarray
            return kthSmallest(arr, l, pos-1, k);

        // Else recur for right subarray
        return kthSmallest(arr, pos+1, r, k-pos+l-1);
    }

    // If k is more than number of elements in array
    return INT_MAX;
}

void swap(int *a, int *b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}

// Standard partition process of QuickSort().  It considers the last
// element as pivot and moves all smaller element to left of it and
// greater elements to right. This function is used by randomPartition()
int partition(int arr[], int l, int r)
{
    int x = arr[r], i = l;
    for (int j = l; j <= r - 1; j++)
    {
        if (arr[j] <= x) //arr[i] is bigger than arr[j] so swap them
        {
            swap(&arr[i], &arr[j]);
            i++;
        }
    }
    swap(&arr[i], &arr[r]); // swap the pivot
    return i;
}

// Picks a random pivot element between l and r and partitions
// arr[l..r] around the randomly picked element using partition()
int randomPartition(int arr[], int l, int r)
{
    int n = r-l+1;
    int pivot = rand() % n;
    swap(&arr[l + pivot], &arr[r]);
    return partition(arr, l, r);
}

// Driver program to test above methods
int main()
{
    int arr[] = {12, 3, 5, 7, 4, 19, 26};
    int n = sizeof(arr)/sizeof(arr[0]), k = 3;
    cout << "K'th smallest element is " << kthSmallest(arr, 0, n-1, k);
    return 0;
}

উপরের সমাধানটির সবচেয়ে খারাপ সময়ের সময়ের জটিলতা এখনও ও (এন 2) worst সবচেয়ে খারাপ ক্ষেত্রে, এলোমেলো ক্রিয়াকলাপটি সর্বদা একটি কোণার উপাদান বেছে নিতে পারে। উপরে র্যান্ডমাইজড কুইকসलेक्टের প্রত্যাশিত সময়ের জটিলতা হ'ল Θ (n)


ভাল কোডিং। ভাগ করে নেওয়ার জন্য ধন্যবাদ, +1
হেনগামে

1
  1. অগ্রাধিকার সারি তৈরি করা আছে।
  2. সমস্ত উপাদান গাদা মধ্যে .োকান।
  3. পোল কল করুন () কে বার।

    public static int getKthLargestElements(int[] arr)
    {
        PriorityQueue<Integer> pq =  new PriorityQueue<>((x , y) -> (y-x));
        //insert all the elements into heap
        for(int ele : arr)
           pq.offer(ele);
        // call poll() k times
        int i=0;
        while(i&lt;k)
         {
           int result = pq.poll();
         } 
       return result;        
    }
    

0

এটি জাভাস্ক্রিপ্টে একটি বাস্তবায়ন।

আপনি যদি অ্যারেটি সংশোধন করতে পারবেন না এমন প্রতিবন্ধকতাটি ছেড়ে দেন তবে "বর্তমান পার্টিশন" সনাক্ত করতে দুটি সূচী ব্যবহার করে অতিরিক্ত মেমরির ব্যবহার প্রতিরোধ করতে পারেন (ক্লাসিক কুইকোর্টোর্ট স্টাইলে - http://www.nczonline.net/blog/2012/ 11/27 / কম্পিউটার-বিজ্ঞান-তে জাভাস্ক্রিপ্ট-কুইকোর্ট / )।

function kthMax(a, k){
    var size = a.length;

    var pivot = a[ parseInt(Math.random()*size) ]; //Another choice could have been (size / 2) 

    //Create an array with all element lower than the pivot and an array with all element higher than the pivot
    var i, lowerArray = [], upperArray = [];
    for (i = 0; i  < size; i++){
        var current = a[i];

        if (current < pivot) {
            lowerArray.push(current);
        } else if (current > pivot) {
            upperArray.push(current);
        }
    }

    //Which one should I continue with?
    if(k <= upperArray.length) {
        //Upper
        return kthMax(upperArray, k);
    } else {
        var newK = k - (size - lowerArray.length);

        if (newK > 0) {
            ///Lower
            return kthMax(lowerArray, newK);
        } else {
            //None ... it's the current pivot!
            return pivot;
        }   
    }
}  

আপনি যদি এটি পরীক্ষা করে দেখতে চান তবে আপনি এই প্রকরণটি ব্যবহার করতে পারেন:

    function kthMax (a, k, logging) {
         var comparisonCount = 0; //Number of comparison that the algorithm uses
         var memoryCount = 0;     //Number of integers in memory that the algorithm uses
         var _log = logging;

         if(k < 0 || k >= a.length) {
            if (_log) console.log ("k is out of range"); 
            return false;
         }      

         function _kthmax(a, k){
             var size = a.length;
             var pivot = a[parseInt(Math.random()*size)];
             if(_log) console.log("Inputs:", a,  "size="+size, "k="+k, "pivot="+pivot);

             // This should never happen. Just a nice check in this exercise
             // if you are playing with the code to avoid never ending recursion            
             if(typeof pivot === "undefined") {
                 if (_log) console.log ("Ops..."); 
                 return false;
             }

             var i, lowerArray = [], upperArray = [];
             for (i = 0; i  < size; i++){
                 var current = a[i];
                 if (current < pivot) {
                     comparisonCount += 1;
                     memoryCount++;
                     lowerArray.push(current);
                 } else if (current > pivot) {
                     comparisonCount += 2;
                     memoryCount++;
                     upperArray.push(current);
                 }
             }
             if(_log) console.log("Pivoting:",lowerArray, "*"+pivot+"*", upperArray);

             if(k <= upperArray.length) {
                 comparisonCount += 1;
                 return _kthmax(upperArray, k);
             } else if (k > size - lowerArray.length) {
                 comparisonCount += 2;
                 return _kthmax(lowerArray, k - (size - lowerArray.length));
             } else {
                 comparisonCount += 2;
                 return pivot;
             }
     /* 
      * BTW, this is the logic for kthMin if we want to implement that... ;-)
      * 

             if(k <= lowerArray.length) {
                 return kthMin(lowerArray, k);
             } else if (k > size - upperArray.length) {
                 return kthMin(upperArray, k - (size - upperArray.length));
             } else 
                 return pivot;
     */            
         }

         var result = _kthmax(a, k);
         return {result: result, iterations: comparisonCount, memory: memoryCount};
     }

বাকি কোডটি কেবল কিছু খেলার মাঠ তৈরি করার জন্য:

    function getRandomArray (n){
        var ar = [];
        for (var i = 0, l = n; i < l; i++) {
            ar.push(Math.round(Math.random() * l))
        }

        return ar;
    }

    //Create a random array of 50 numbers
    var ar = getRandomArray (50);   

এখন, আপনি কয়েকবার পরীক্ষা চালান। ম্যাথ.র্যান্ডম () এর কারণে এটি প্রতিবার ভিন্ন ফলাফল এনে দেবে:

    kthMax(ar, 2, true);
    kthMax(ar, 2);
    kthMax(ar, 2);
    kthMax(ar, 2);
    kthMax(ar, 2);
    kthMax(ar, 2);
    kthMax(ar, 34, true);
    kthMax(ar, 34);
    kthMax(ar, 34);
    kthMax(ar, 34);
    kthMax(ar, 34);
    kthMax(ar, 34);

যদি আপনি এটি কয়েকবার পরীক্ষা করেন তবে আপনি আরও অভিজ্ঞতার সাথে দেখতে পাবেন যে পুনরাবৃত্তির সংখ্যা, গড়ে, ও (এন) constant = ধ্রুবক * এন এবং কে এর মান অ্যালগোরিদমকে প্রভাবিত করে না।


0

আমি এই অ্যালগরিদমটি নিয়ে এসেছি এবং ও (এন) বলে মনে হচ্ছে:

আসুন কে = 3 বলুন এবং আমরা অ্যারেতে তৃতীয় বৃহত্তম আইটেমটি খুঁজতে চাই। আমি তিনটি ভেরিয়েবল তৈরি করব এবং অ্যারের প্রতিটি আইটেমকে এই তিনটি ভেরিয়েবলের ন্যূনতম সাথে তুলনা করব। অ্যারে আইটেমটি যদি আমাদের সর্বনিম্নের চেয়ে বড় হয় তবে আমরা ন্যূনতম ভেরিয়েবলটি আইটেমের মানের সাথে প্রতিস্থাপন করব। অ্যারের শেষ হওয়া পর্যন্ত আমরা একই জিনিস চালিয়ে যাচ্ছি। আমাদের তিনটি ভেরিয়েবলের সর্বনিম্ন হ'ল অ্যারের 3 য় বৃহত্তম আইটেম।

define variables a=0, b=0, c=0
iterate through the array items
    find minimum a,b,c
    if item > min then replace the min variable with item value
    continue until end of array
the minimum of a,b,c is our answer

এবং, Kth বৃহত্তম আইটেম সন্ধান করতে আমাদের কে ভেরিয়েবলগুলি দরকার।

উদাহরণ: (কে = 3)

[1,2,4,1,7,3,9,5,6,2,9,8]

Final variable values:

a=7 (answer)
b=8
c=9

কেউ দয়া করে এটি পর্যালোচনা করতে পারেন এবং আমাকে কী মিস করছি তা আমাকে জানান?


0

প্রস্তাবিত অ্যালগরিদম এলাদভের বাস্তবায়ন এখানে দেওয়া হয়েছে (আমি বাস্তবায়নটি এলোমেলো পিভট সহ এখানেও রেখেছি):

public class Median {

    public static void main(String[] s) {

        int[] test = {4,18,20,3,7,13,5,8,2,1,15,17,25,30,16};
        System.out.println(selectK(test,8));

        /*
        int n = 100000000;
        int[] test = new int[n];
        for(int i=0; i<test.length; i++)
            test[i] = (int)(Math.random()*test.length);

        long start = System.currentTimeMillis();
        random_selectK(test, test.length/2);
        long end = System.currentTimeMillis();
        System.out.println(end - start);
        */
    }

    public static int random_selectK(int[] a, int k) {
        if(a.length <= 1)
            return a[0];

        int r = (int)(Math.random() * a.length);
        int p = a[r];

        int small = 0, equal = 0, big = 0;
        for(int i=0; i<a.length; i++) {
            if(a[i] < p) small++;
            else if(a[i] == p) equal++;
            else if(a[i] > p) big++;
        }

        if(k <= small) {
            int[] temp = new int[small];
            for(int i=0, j=0; i<a.length; i++)
                if(a[i] < p)
                    temp[j++] = a[i];
            return random_selectK(temp, k);
        }

        else if (k <= small+equal)
            return p;

        else {
            int[] temp = new int[big];
            for(int i=0, j=0; i<a.length; i++)
                if(a[i] > p)
                    temp[j++] = a[i];
            return random_selectK(temp,k-small-equal);
        }
    }

    public static int selectK(int[] a, int k) {
        if(a.length <= 5) {
            Arrays.sort(a);
            return a[k-1];
        }

        int p = median_of_medians(a);

        int small = 0, equal = 0, big = 0;
        for(int i=0; i<a.length; i++) {
            if(a[i] < p) small++;
            else if(a[i] == p) equal++;
            else if(a[i] > p) big++;
        }

        if(k <= small) {
            int[] temp = new int[small];
            for(int i=0, j=0; i<a.length; i++)
                if(a[i] < p)
                    temp[j++] = a[i];
            return selectK(temp, k);
        }

        else if (k <= small+equal)
            return p;

        else {
            int[] temp = new int[big];
            for(int i=0, j=0; i<a.length; i++)
                if(a[i] > p)
                    temp[j++] = a[i];
            return selectK(temp,k-small-equal);
        }
    }

    private static int median_of_medians(int[] a) {
        int[] b = new int[a.length/5];
        int[] temp = new int[5];
        for(int i=0; i<b.length; i++) {
            for(int j=0; j<5; j++)
                temp[j] = a[5*i + j];
            Arrays.sort(temp);
            b[i] = temp[2];
        }

        return selectK(b, b.length/2 + 1);
    }
}

0

এটি কুইকসোর্ট কৌশল হিসাবে সাদৃশ্য, যেখানে আমরা একটি স্বেচ্ছাসেবক পাইভট বাছাই করি এবং তার বামে ছোট উপাদানগুলি আনব এবং ডানদিকে আরও বড়

    public static int kthElInUnsortedList(List<int> list, int k)
    {
        if (list.Count == 1)
            return list[0];

        List<int> left = new List<int>();
        List<int> right = new List<int>();

        int pivotIndex = list.Count / 2;
        int pivot = list[pivotIndex]; //arbitrary

        for (int i = 0; i < list.Count && i != pivotIndex; i++)
        {
            int currentEl = list[i];
            if (currentEl < pivot)
                left.Add(currentEl);
            else
                right.Add(currentEl);
        }

        if (k == left.Count + 1)
            return pivot;

        if (left.Count < k)
            return kthElInUnsortedList(right, k - left.Count - 1);
        else
            return kthElInUnsortedList(left, k);
    }


0

ও (এন) সময় এবং ধ্রুবক স্পেসে আপনি kth ক্ষুদ্রতম উপাদানটি খুঁজে পেতে পারেন। যদি আমরা অ্যারে বিবেচনা করি তবে কেবল পূর্ণসংখ্যার জন্য।

পদ্ধতির হ'ল অ্যারে মানগুলির ব্যাপ্তিতে বাইনারি অনুসন্ধান করা। আমাদের যদি একটি পূর্ণসংখ্যার পরিসরে একটি মিনি_ভ্যালু এবং একটি সর্বাধিক মানের দুটি থাকে তবে আমরা সেই ব্যাপ্তিতে বাইনারি অনুসন্ধান করতে পারি। আমরা একটি তুলনামূলক ফাংশন লিখতে পারি যা আমাদের জানায় যে কোনও মান kth- ক্ষুদ্রতম বা kth- ক্ষুদ্রতম চেয়ে ছোট বা kth- ক্ষুদ্রতমের চেয়ে বড়। আপনি কেটি-ক্ষুদ্রতম সংখ্যায় না পৌঁছা পর্যন্ত বাইনারি অনুসন্ধান করুন

এখানে তার জন্য কোড

ক্লাস সমাধান:

def _iskthsmallest(self, A, val, k):
    less_count, equal_count = 0, 0
    for i in range(len(A)):
        if A[i] == val: equal_count += 1
        if A[i] < val: less_count += 1

    if less_count >= k: return 1
    if less_count + equal_count < k: return -1
    return 0

def kthsmallest_binary(self, A, min_val, max_val, k):
    if min_val == max_val:
        return min_val
    mid = (min_val + max_val)/2
    iskthsmallest = self._iskthsmallest(A, mid, k)
    if iskthsmallest == 0: return mid
    if iskthsmallest > 0: return self.kthsmallest_binary(A, min_val, mid, k)
    return self.kthsmallest_binary(A, mid+1, max_val, k)

# @param A : tuple of integers
# @param B : integer
# @return an integer
def kthsmallest(self, A, k):
    if not A: return 0
    if k > len(A): return 0
    min_val, max_val = min(A), max(A)
    return self.kthsmallest_binary(A, min_val, max_val, k)

0

একটি অ্যালগরিদমও রয়েছে, যা কুইকসিলেক্ট অ্যালগরিদমকে ছাড়িয়ে যায়। একে ফ্লয়েড-রিভেটস (এফআর) অ্যালগরিদম বলা হয়

মূল নিবন্ধ: https://doi.org/10.1145/360680.360694

ডাউনলোডযোগ্য সংস্করণ: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.309.7108&rep=rep1&type=pdf

উইকিপিডিয়া নিবন্ধ https://en.wikedia.org/wiki/Floyd%E2%80%93 রিভেস্ট_ালগোরিদম

আমি সি ++ এ কুইক সিলেক্ট এবং এফআর অ্যালগরিদম বাস্তবায়নের চেষ্টা করেছি। এছাড়াও আমি তাদের স্ট্যান্ডার্ড সি ++ লাইব্রেরি বাস্তবায়নের সাথে তুলনা করেছি std :: nth_element (যা মূলত কুইক সিলেক্ট এবং হিপসलेक्टের ইন্ট্রোসিলিট হাইব্রিড)। ফলাফলটি দ্রুত নির্বাচিত হয়েছিল এবং n তম এলিমেন্ট গড় তুলনামূলকভাবে চলেছিল, তবে এফআর অ্যালগরিদম আনুমানিক প্রায় চলেছে। তাদের তুলনায় দ্বিগুণ দ্রুত।

নমুনা কোড যা আমি এফআর অ্যালগরিদমের জন্য ব্যবহার করেছি:

template <typename T>
T FRselect(std::vector<T>& data, const size_t& n)
{
    if (n == 0)
        return *(std::min_element(data.begin(), data.end()));
    else if (n == data.size() - 1)
        return *(std::max_element(data.begin(), data.end()));
    else
        return _FRselect(data, 0, data.size() - 1, n);
}

template <typename T>
T _FRselect(std::vector<T>& data, const size_t& left, const size_t& right, const size_t& n)
{
    size_t leftIdx = left;
    size_t rightIdx = right;

    while (rightIdx > leftIdx)
    {
        if (rightIdx - leftIdx > 600)
        {
            size_t range = rightIdx - leftIdx + 1;
            long long i = n - (long long)leftIdx + 1;
            long long z = log(range);
            long long s = 0.5 * exp(2 * z / 3);
            long long sd = 0.5 * sqrt(z * s * (range - s) / range) * sgn(i - (long long)range / 2);

            size_t newLeft = fmax(leftIdx, n - i * s / range + sd);
            size_t newRight = fmin(rightIdx, n + (range - i) * s / range + sd);

            _FRselect(data, newLeft, newRight, n);
        }
        T t = data[n];
        size_t i = leftIdx;
        size_t j = rightIdx;
        // arrange pivot and right index
        std::swap(data[leftIdx], data[n]);
        if (data[rightIdx] > t)
            std::swap(data[rightIdx], data[leftIdx]);

        while (i < j)
        {
            std::swap(data[i], data[j]);
            ++i; --j;
            while (data[i] < t) ++i;
            while (data[j] > t) --j;
        }

        if (data[leftIdx] == t)
            std::swap(data[leftIdx], data[j]);
        else
        {
            ++j;
            std::swap(data[j], data[rightIdx]);
        }
        // adjust left and right towards the boundaries of the subset
        // containing the (k - left + 1)th smallest element
        if (j <= n)
            leftIdx = j + 1;
        if (n <= j)
            rightIdx = j - 1;
    }

    return data[leftIdx];
}

template <typename T>
int sgn(T val) {
    return (T(0) < val) - (val < T(0));
}

-1

আমি যা করবো তা হ'ল:

initialize empty doubly linked list l
for each element e in array
    if e larger than head(l)
        make e the new head of l
        if size(l) > k
            remove last element from l

the last element of l should now be the kth largest element

আপনি কেবল লিঙ্কযুক্ত তালিকায় প্রথম এবং শেষ উপাদানটির জন্য পয়েন্টারগুলি সঞ্চয় করতে পারেন। তালিকার আপডেটগুলি করা হলে এগুলি পরিবর্তন হয়।

হালনাগাদ:

initialize empty sorted tree l
for each element e in array
    if e between head(l) and tail(l)
        insert e into l // O(log k)
        if size(l) > k
            remove last element from l

the last element of l should now be the kth largest element

E যদি মাথা (l) এর চেয়ে ছোট হয়? এটি এখনও kth বৃহত্তম উপাদান থেকে বড় হতে পারে, কিন্তু কখনও এই তালিকায় যুক্ত হবে না। এটি কাজ করার জন্য আপনাকে ক্রমহীন ক্রম অনুসারে আইটেমের তালিকাটি বাছাই করতে হবে।
এলি

আপনি ঠিক বলেছেন, অনুমান করুন আমার আরও কিছু মাধ্যমে এটি চিন্তা করা প্রয়োজন। :-)
জেস্পার বেকার 21

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

-1

প্রথমে আমরা অনিবন্ধিত অ্যারে থেকে একটি বিএসটি তৈরি করতে পারি যা ও (এন) সময় লাগে এবং বিএসটি থেকে আমরা ও (লগ (এন)) এর মধ্যে kth ক্ষুদ্রতম উপাদান খুঁজে পেতে পারি যা সমস্ত পরিমাণকে ও (এন) এর ক্রম হিসাবে গণ্য করে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.