दो क्रमबद्ध सरणियों के मिलन में kth सबसे छोटे तत्व को कैसे खोजें?


106

यह एक होमवर्क प्रश्न है। वे कहते हैं कि यह लेता है O(logN + logM), जहां Nऔर Mसरणियों समान नहीं हैं।

आइए सरणियों को नाम दें aऔर b। जाहिर है हम सभी को नजरअंदाज कर सकते हैं a[i]और b[i]जहां मैं> के।
पहले की तुलना करते हैं a[k/2]और b[k/2]। चलो b[k/2]> a[k/2]। इसलिए हम सभी को भी छोड़ सकते हैं b[i], जहां मैं> k / 2।

अब हमारे पास सब है a[i], जहाँ मैं <k और सभी b[i], जहाँ i <k / 2 उत्तर खोजने के लिए।

अगला कदम क्या है?


6
क्या ये सभी चरण असाइनमेंट में शामिल थे, या उपरोक्त चरण आपके एल्गोरिथम की शुरुआत हैं?
केंड्रिक

18
ऊपर के चरण मेरे हैं।
माइकल

क्या O(logN + logM)केवल उस तत्व को खोजने में लगने वाले समय का जिक्र है? क्या प्रीप्रोसेसिंग पहले से संघ के लिए किया जा सकता है?
डेविड वेसर

1
@ दाऊद। कोई प्रीप्रोसेसिंग अपेक्षित नहीं है।
माइकल

3
क्या सरणियों में डुप्लिकेट की अनुमति है?
डेविड वीज़र

जवाबों:


48

तुम्हें मिल गया है, बस चलते रहो! और इंडेक्स के साथ सावधान रहें ...

थोड़ा सरल करने के लिए मैं मान लूंगा कि N और M> k हैं, इसलिए यहां जटिलता O (लॉग k) है, जो O (लॉग एन + लॉग एम) है।

छद्म कोड:

i = k/2
j = k - i
step = k/4
while step > 0
    if a[i-1] > b[j-1]
        i -= step
        j += step
    else
        i += step
        j -= step
    step /= 2

if a[i-1] > b[j-1]
    return a[i-1]
else
    return b[j-1]

प्रदर्शन के लिए आप लूप इनवेरिएंट i + j = k का उपयोग कर सकते हैं, लेकिन मैं आपके सभी होमवर्क नहीं करूंगा :)


14
यह एक वास्तविक प्रमाण नहीं है, लेकिन एल्गोरिथ्म के पीछे का विचार यह है कि हम i + j = k को बनाए रखते हैं, और ऐसे i और j को ढूंढते हैं ताकि एक [i-1] <b [j-1] <a [i] ( या दूसरा रास्ता गोल)। अब चूँकि मैं 'a' में 'b' से छोटा [j-1], और j-1 में 'b' से छोटा [j-1], b [j-1] i + j-1 के तत्व हैं। + 1 = kth सबसे छोटा तत्व। इस तरह के i को खोजने के लिए, j एल्गोरिथ्म सरणियों पर एक द्विध्रुवीय खोज करता है। समझ में आता है?
जूल्स ओलेओन

8
ओ (लॉग के) ओ कैसे है (लॉग एन + लॉग एम)?
राजेंद्र उप्पल

7
यह काम नहीं करता है यदि सरणी 1 में सभी मान सरणी 2 में मानों से पहले आते हैं
जॉन कुर्लाक

3
आपने पहले चरण में k / 4 का उपयोग क्यों किया?
मैगी

2
के रूप में उल्लेख किया @JohnKurlak यह मान के लिए काम करते हैं जहां पूरे एक ख से छोटी है देख नहीं करता है repl.it/HMYf/0
जेरेमी एस

69

मुझे उम्मीद है कि मैं आपके होमवर्क का जवाब नहीं दे रहा हूं क्योंकि यह सवाल पूछे जाने के बाद एक साल से अधिक हो गया है। यहाँ एक पूंछ पुनरावर्ती समाधान है जो लॉग (len (a) + len (b)) समय लेगा।

धारणा: इनपुट सही हैं। यानी k की सीमा में है [0, len (a) + len (b)]

आधार मामले:

  • यदि सरणियों में से एक की लंबाई 0 है, तो उत्तर दूसरे सरणी का kth तत्व है।

कटौती कदम:

  • यदि का मिड इंडेक्स a+ के मिड इंडेक्स से bकम हैk
    • यदि का मध्य तत्व मध्य तत्व से aअधिक है b, तो हम पहली छमाही को अनदेखा कर सकते हैं b, समायोजित कर सकते हैं k
    • और पहले छमाही को अनदेखा करें a, समायोजित करें k
  • यदि kमध्य सूचकांकों के योग से कम है aऔर b:
    • यदि मध्य तत्व के मध्य तत्व से aअधिक है b, तो हम सुरक्षित रूप से दूसरी छमाही की उपेक्षा कर सकते हैंa
    • वरना हम दूसरी छमाही की अनदेखी कर सकते हैं b

कोड:

def kthlargest(arr1, arr2, k):
    if len(arr1) == 0:
        return arr2[k]
    elif len(arr2) == 0:
        return arr1[k]

    mida1 = len(arr1)/2
    mida2 = len(arr2)/2
    if mida1+mida2<k:
        if arr1[mida1]>arr2[mida2]:
            return kthlargest(arr1, arr2[mida2+1:], k-mida2-1)
        else:
            return kthlargest(arr1[mida1+1:], arr2, k-mida1-1)
    else:
        if arr1[mida1]>arr2[mida2]:
            return kthlargest(arr1[:mida1], arr2, k)
        else:
            return kthlargest(arr1, arr2[:mida2], k)

कृपया ध्यान दें कि मेरा समाधान हर कॉल में छोटे सरणियों की नई प्रतियां बना रहा है, इसे मूल सरणियों पर केवल पासिंग स्टार्ट और एंड इंडिक्स द्वारा आसानी से समाप्त किया जा सकता है।


4
आप इसे क्यों कहते हैं, यह सबसे छोटे तत्वों को kthlargest()रिटर्न (k+1)करता है, उदाहरण के लिए , आपका फ़ंक्शन रिटर्न 1में दूसरा सबसे छोटा तत्व है । 0,1,2,3sorted(a+b)[k]
jfs

2
मैंने आपका कोड C ++ में बदल दिया है । यह काम करने लगता है
JFS

1
क्या आप बता सकते हैं कि k के साथ a और b के मध्य इंडेक्स के योग की तुलना करना क्यों महत्वपूर्ण है?
मैगी

3
कटौती चरणों में, रन-टाइम लॉगरिदमिक बनाने के लिए इसकी लंबाई के आनुपातिक में से एक में कई तत्वों से छुटकारा पाना महत्वपूर्ण है। (यहाँ हम आधे से छुटकारा पा रहे हैं)। ऐसा करने के लिए, हमें एक सरणी का चयन करने की आवश्यकता है जिसका आधा भाग हम सुरक्षित रूप से अनदेखा कर सकते हैं। हम यह कैसे करे? आत्मविश्वास से आधे को खत्म करने के लिए हम जानते हैं कि यह तत्व नहीं है।
लैंबडापिलग्रिम 18

1
सरणियों के आधे-लम्बाई के योग के साथ k की तुलना करने से हमें इस बात की जानकारी मिलती है कि कौन-सी सरणियों में से आधे को समाप्त किया जा सकता है। यदि k आधी-लंबाई के योग से बड़ा है, तो हम जानते हैं कि किसी एक सरणियों के पहले आधे को समाप्त किया जा सकता है। यदि कश्मीर छोटा है, तो इसके विपरीत। ध्यान दें कि हम एक बार में प्रत्येक सरणी से एक आधा समाप्त नहीं कर सकते। यह तय करने के लिए कि किस सरणी के आधे हिस्से को समाप्त करने के लिए, हम इस तथ्य का लाभ उठाते हैं कि दोनों सरणियों को क्रमबद्ध किया गया है, इसलिए यदि k आधी लंबाई के योग से बड़ा है, तो हम सरणी के पहले आधे भाग को समाप्त कर सकते हैं जिसका मध्य तत्व छोटा है दो मध्य तत्व। विपरीतता से।
लैंबडापिलग्रिम 19

34

कई लोगों ने इस "केएचटी स्मॉलटेस्ट एलिमेंट फ्रॉम दो सॉर्ट्ड एरे" सवाल का जवाब दिया, लेकिन आमतौर पर केवल सामान्य विचारों के साथ, एक स्पष्ट कार्य कोड या सीमा की स्थिति विश्लेषण नहीं।

यहाँ मैं इसे ध्यान से विस्तृत करना चाहता हूँ जिस तरह से मैं गया हालांकि कुछ नौसिखियों को समझने में मदद करने के लिए, मेरे सही काम करने वाले जावा कोड के साथ। A1और A2दो क्रमबद्ध आरोही सरणियाँ हैं, क्रमशः size1और size2लंबाई के रूप में। हमें उन दो सरणियों के मिलन से k-th सबसे छोटे तत्व को खोजने की जरूरत है। यहाँ हम यथोचित मान लेते हैं कि (k > 0 && k <= size1 + size2), जो कि निकलता है A1और A2दोनों खाली नहीं हो सकता।

सबसे पहले, आइए इस प्रश्न को एक धीमी O (k) एल्गोरिथ्म के साथ करें। विधि दोनों सरणी के पहले तत्व की तुलना करने के लिए है, A1[0]और A2[0]। छोटे को ले लो, A1[0]हमारी जेब में कहो । फिर के A1[1]साथ तुलना करें A2[0], और इसी तरह। इस क्रिया को तब तक दोहराएं जब तक कि हमारी जेब kतत्वों तक न पहुंच जाए । बहुत महत्वपूर्ण: पहले चरण में, हम केवल A1[0]अपनी जेब में कर सकते हैं । हम शामिल या बाहर नहीं कर सकते हैं A2[0]!!!

निम्नलिखित O (k) कोड आपको सही उत्तर से पहले एक तत्व देता है। यहाँ मैं इसका उपयोग अपने विचार दिखाने के लिए करता हूं, और सीमा स्थिति का विश्लेषण करता हूं। मेरे पास इसके बाद सही कोड है:

private E kthSmallestSlowWithFault(int k) {
    int size1 = A1.length, size2 = A2.length;

    int index1 = 0, index2 = 0;
    // base case, k == 1
    if (k == 1) {
        if (size1 == 0) {
            return A2[index2];
        } else if (size2 == 0) {
            return A1[index1];
        } else if (A1[index1].compareTo(A2[index2]) < 0) {
            return A1[index1];
        } else {
            return A2[index2];
        }
    }

    /* in the next loop, we always assume there is one next element to compare with, so we can
     * commit to the smaller one. What if the last element is the kth one?
     */
    if (k == size1 + size2) {
        if (size1 == 0) {
            return A2[size2 - 1];
        } else if (size2 == 0) {
            return A1[size1 - 1];
        } else if (A1[size1 - 1].compareTo(A2[size2 - 1]) < 0) {
            return A1[size1 - 1];
        } else {
            return A2[size2 - 1];
        }
    }

    /*
     * only when k > 1, below loop will execute. In each loop, we commit to one element, till we
     * reach (index1 + index2 == k - 1) case. But the answer is not correct, always one element
     * ahead, because we didn't merge base case function into this loop yet.
     */
    int lastElementFromArray = 0;
    while (index1 + index2 < k - 1) {
        if (A1[index1].compareTo(A2[index2]) < 0) {
            index1++;
            lastElementFromArray = 1;
            // commit to one element from array A1, but that element is at (index1 - 1)!!!
        } else {
            index2++;
            lastElementFromArray = 2;
        }
    }
    if (lastElementFromArray == 1) {
        return A1[index1 - 1];
    } else {
        return A2[index2 - 1];
    }
}

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

उपरोक्त कोड आधार मामले का अवलोकन करके k == 1, k == size1+size2 , और उसके साथ गठबंधन करें A1और A2दोनों खाली नहीं हो सकते। हम तर्क को और अधिक संक्षिप्त शैली में बदल सकते हैं।

यहाँ एक धीमी लेकिन सही कार्य कोड है:

private E kthSmallestSlow(int k) {
    // System.out.println("this is an O(k) speed algorithm, very concise");
    int size1 = A1.length, size2 = A2.length;

    int index1 = 0, index2 = 0;
    while (index1 + index2 < k - 1) {
        if (size1 > index1 && (size2 <= index2 || A1[index1].compareTo(A2[index2]) < 0)) {
            index1++; // here we commit to original index1 element, not the increment one!!!
        } else {
            index2++;
        }
    }
    // below is the (index1 + index2 == k - 1) base case
    // also eliminate the risk of referring to an element outside of index boundary
    if (size1 > index1 && (size2 <= index2 || A1[index1].compareTo(A2[index2]) < 0)) {
        return A1[index1];
    } else {
        return A2[index2];
    }
}

अब हम O (लॉग k) पर तेज़ एल्गोरिदम चला सकते हैं। इसी तरह, के A1[k/2]साथ तुलना करें A2[k/2]; अगर A1[k/2]छोटी है, तब से सभी तत्वों A1[0]के लिए A1[k/2]हमारे जेब में होना चाहिए। यह विचार प्रत्येक लूप में केवल एक तत्व के लिए प्रतिबद्ध नहीं है; पहले चरण में k/2तत्व शामिल हैं। फिर से, हम शामिल या बहिष्कृत नहीं कर सकतेA2[0] करने के लिए A2[k/2]वैसे भी। इसलिए पहले चरण में, हम k/2तत्वों से अधिक नहीं जा सकते । दूसरे चरण के लिए, हम k/4तत्वों से अधिक नहीं जा सकते ...

प्रत्येक चरण के बाद, हम k-th तत्व के बहुत करीब पहुंच जाते हैं। उसी समय तक प्रत्येक चरण छोटा और छोटा हो जाता है, जब तक हम नहीं पहुंचते(step == 1) , जो है (k-1 == index1+index2)। फिर हम सरल और शक्तिशाली आधार मामले को फिर से संदर्भित कर सकते हैं।

यहाँ काम कर सही कोड है:

private E kthSmallestFast(int k) {
    // System.out.println("this is an O(log k) speed algorithm with meaningful variables name");
    int size1 = A1.length, size2 = A2.length;

    int index1 = 0, index2 = 0, step = 0;
    while (index1 + index2 < k - 1) {
        step = (k - index1 - index2) / 2;
        int step1 = index1 + step;
        int step2 = index2 + step;
        if (size1 > step1 - 1
                && (size2 <= step2 - 1 || A1[step1 - 1].compareTo(A2[step2 - 1]) < 0)) {
            index1 = step1; // commit to element at index = step1 - 1
        } else {
            index2 = step2;
        }
    }
    // the base case of (index1 + index2 == k - 1)
    if (size1 > index1 && (size2 <= index2 || A1[index1].compareTo(A2[index2]) < 0)) {
        return A1[index1];
    } else {
        return A2[index2];
    }
}

कुछ लोगों को चिंता हो सकती है कि क्या हो (index1+index2) k-1 पर कूद जाए? क्या हम आधार मामले को याद कर सकते हैं (k-1 == index1+index2)? यह असंभव है। आप 0.5 + 0.25 + 0.125 जोड़ सकते हैं ..., और आप 1 से आगे कभी नहीं जाएंगे।

बेशक, उपरोक्त कोड को पुनरावर्ती एल्गोरिदम में बदलना बहुत आसान है:

private E kthSmallestFastRecur(int k, int index1, int index2, int size1, int size2) {
    // System.out.println("this is an O(log k) speed algorithm with meaningful variables name");

    // the base case of (index1 + index2 == k - 1)
    if (index1 + index2 == k - 1) {
        if (size1 > index1 && (size2 <= index2 || A1[index1].compareTo(A2[index2]) < 0)) {
            return A1[index1];
        } else {
            return A2[index2];
        }
    }

    int step = (k - index1 - index2) / 2;
    int step1 = index1 + step;
    int step2 = index2 + step;
    if (size1 > step1 - 1 && (size2 <= step2 - 1 || A1[step1 - 1].compareTo(A2[step2 - 1]) < 0)) {
        index1 = step1;
    } else {
        index2 = step2;
    }
    return kthSmallestFastRecur(k, index1, index2, size1, size2);
}

आशा है कि उपरोक्त विश्लेषण और जावा कोड आपको समझने में मदद कर सकते हैं। लेकिन मेरे कोड को कभी भी अपने होमवर्क के रूप में कॉपी न करें! चीयर्स;)


1
आपके महान स्पष्टीकरण और उत्तर के लिए बहुत बहुत धन्यवाद, +1 :)
हेंगामेह

पहले कोड में, के else if (A1[size1 - 1].compareTo(A2[size2 - 1]) < 0) बजाय नहीं होना चाहिए else if (A1[size1 - 1].compareTo(A2[size2 - 1]) > 0)? (KthSmallestSlowWithFault कोड में)
हेंगामेह

शुक्रिया @Fei महान व्याख्या। यह आश्चर्यजनक है कि इस समस्या के बारे में इंटरनेट पर कितने गलत उत्तर प्रसारित हो रहे हैं। यह और भी हैरान करने वाला है कि इस सवाल को लेकर एसओ ने जो जवाब दिया, वह हमेशा गलत है। लगता है जैसे किसी को भी उत्तरों की परख करने की परवाह नहीं है।
कप्तान फोगेट्टी

हो सकता है कि कुछ चरणों (15 कहा) के बाद ओ (के) समाधान के लिए कटऑफ, क्योंकि चरण सीमा बहुत तेजी से घटती है।
स्काई

1
किसी भी पुनरावर्ती कॉल में A1 या A2 का आकार कम नहीं होता है।
आदित्य जोशी

5

यहाँ @ lambdapilgrim के समाधान का C ++ पुनरावृत्त संस्करण है (वहाँ एल्गोरिथ्म का स्पष्टीकरण देखें):

#include <cassert>
#include <iterator>

template<class RandomAccessIterator, class Compare>
typename std::iterator_traits<RandomAccessIterator>::value_type
nsmallest_iter(RandomAccessIterator firsta, RandomAccessIterator lasta,
               RandomAccessIterator firstb, RandomAccessIterator lastb,
               size_t n,
               Compare less) {
  assert(issorted(firsta, lasta, less) && issorted(firstb, lastb, less));
  for ( ; ; ) {
    assert(n < static_cast<size_t>((lasta - firsta) + (lastb - firstb)));
    if (firsta == lasta) return *(firstb + n);
    if (firstb == lastb) return *(firsta + n);

    size_t mida = (lasta - firsta) / 2;
    size_t midb = (lastb - firstb) / 2;
    if ((mida + midb) < n) {
      if (less(*(firstb + midb), *(firsta + mida))) {
        firstb += (midb + 1);
        n -= (midb + 1);
      }
      else {
        firsta += (mida + 1);
        n -= (mida + 1);
      }
    }
    else {
      if (less(*(firstb + midb), *(firsta + mida)))
        lasta = (firsta + mida);
      else
        lastb = (firstb + midb);
    }
  }
}

यह सभी 0 <= n < (size(a) + size(b))अनुक्रमित और के लिए काम करता हैO(log(size(a)) + log(size(b))) जटिलता है।

उदाहरण

#include <functional> // greater<>
#include <iostream>

#define SIZE(a) (sizeof(a) / sizeof(*a))

int main() {
  int a[] = {5,4,3};
  int b[] = {2,1,0};
  int k = 1; // find minimum value, the 1st smallest value in a,b

  int i = k - 1; // convert to zero-based indexing
  int v = nsmallest_iter(a, a + SIZE(a), b, b + SIZE(b),
                         SIZE(a)+SIZE(b)-1-i, std::greater<int>());
  std::cout << v << std::endl; // -> 0
  return v;
}

4

पहले k नंबरों के लिए मेरा प्रयास, 2 क्रमबद्ध सरणियों में kth संख्या, और n क्रमबद्ध सरणियों में:

// require() is recognizable by node.js but not by browser;
// for running/debugging in browser, put utils.js and this file in <script> elements,
if (typeof require === "function") require("./utils.js");

// Find K largest numbers in two sorted arrays.
function k_largest(a, b, c, k) {
    var sa = a.length;
    var sb = b.length;
    if (sa + sb < k) return -1;
    var i = 0;
    var j = sa - 1;
    var m = sb - 1;
    while (i < k && j >= 0 && m >= 0) {
        if (a[j] > b[m]) {
            c[i] = a[j];
            i++;
            j--;
        } else {
            c[i] = b[m];
            i++;
            m--;
        }
    }
    debug.log(2, "i: "+ i + ", j: " + j + ", m: " + m);
    if (i === k) {
        return 0;
    } else if (j < 0) {
        while (i < k) {
            c[i++] = b[m--];
        }
    } else {
        while (i < k) c[i++] = a[j--];
    }
    return 0;
}

// find k-th largest or smallest number in 2 sorted arrays.
function kth(a, b, kd, dir){
    sa = a.length; sb = b.length;
    if (kd<1 || sa+sb < kd){
        throw "Mission Impossible! I quit!";
    }

    var k;
    //finding the kd_th largest == finding the smallest k_th;
    if (dir === 1){ k = kd;
    } else if (dir === -1){ k = sa + sb - kd + 1;}
    else throw "Direction has to be 1 (smallest) or -1 (largest).";

    return find_kth(a, b, k, sa-1, 0, sb-1, 0);
}

// find k-th smallest number in 2 sorted arrays;
function find_kth(c, d, k, cmax, cmin, dmax, dmin){

    sc = cmax-cmin+1; sd = dmax-dmin+1; k0 = k; cmin0 = cmin; dmin0 = dmin;
    debug.log(2, "=k: " + k +", sc: " + sc + ", cmax: " + cmax +", cmin: " + cmin + ", sd: " + sd +", dmax: " + dmax + ", dmin: " + dmin);

    c_comp = k0-sc;
    if (c_comp <= 0){
        cmax = cmin0 + k0-1;
    } else {
        dmin = dmin0 + c_comp-1;
        k -= c_comp-1;
    }

    d_comp = k0-sd;
    if (d_comp <= 0){
        dmax = dmin0 + k0-1;
    } else {
        cmin = cmin0 + d_comp-1;
        k -= d_comp-1;
    }
    sc = cmax-cmin+1; sd = dmax-dmin+1;

    debug.log(2, "#k: " + k +", sc: " + sc + ", cmax: " + cmax +", cmin: " + cmin + ", sd: " + sd +", dmax: " + dmax + ", dmin: " + dmin + ", c_comp: " + c_comp + ", d_comp: " + d_comp);

    if (k===1) return (c[cmin]<d[dmin] ? c[cmin] : d[dmin]);
    if (k === sc+sd) return (c[cmax]>d[dmax] ? c[cmax] : d[dmax]);

    m = Math.floor((cmax+cmin)/2);
    n = Math.floor((dmax+dmin)/2);

    debug.log(2, "m: " + m + ", n: "+n+", c[m]: "+c[m]+", d[n]: "+d[n]);

    if (c[m]<d[n]){
        if (m === cmax){ // only 1 element in c;
            return d[dmin+k-1];
        }

        k_next = k-(m-cmin+1);
        return find_kth(c, d, k_next, cmax, m+1, dmax, dmin);
    } else {
        if (n === dmax){
            return c[cmin+k-1];
        }

        k_next = k-(n-dmin+1);
        return find_kth(c, d, k_next, cmax, cmin, dmax, n+1);
    }
}

function traverse_at(a, ae, h, l, k, at, worker, wp){
    var n = ae ? ae.length : 0;
    var get_node;
    switch (at){
        case "k": get_node = function(idx){
                var node = {};
                var pos = l[idx] + Math.floor(k/n) - 1;
                if (pos<l[idx]){ node.pos = l[idx]; }
                else if (pos > h[idx]){ node.pos = h[idx];}
                else{ node.pos = pos; }

                node.idx = idx;
                node.val = a[idx][node.pos];
                debug.log(6, "pos: "+pos+"\nnode =");
                debug.log(6, node);
                return node;
            };
            break;
        case "l": get_node = function(idx){
                debug.log(6, "a["+idx+"][l["+idx+"]]: "+a[idx][l[idx]]);
                return a[idx][l[idx]];
            };
            break;
        case "h": get_node = function(idx){
                debug.log(6, "a["+idx+"][h["+idx+"]]: "+a[idx][h[idx]]);
                return a[idx][h[idx]];
            };
            break;
        case "s": get_node = function(idx){
                debug.log(6, "h["+idx+"]-l["+idx+"]+1: "+(h[idx] - l[idx] + 1));
                return h[idx] - l[idx] + 1;
            };
            break;
        default: get_node = function(){
                debug.log(1, "!!! Exception: get_node() returns null.");
                return null;
            };
            break;
    }

    worker.init();

    debug.log(6, "--* traverse_at() *--");

    var i;
    if (!wp){
        for (i=0; i<n; i++){
            worker.work(get_node(ae[i]));
        }    
    } else {
        for (i=0; i<n; i++){
            worker.work(get_node(ae[i]), wp);
        }
    }

    return worker.getResult();
}

sumKeeper = function(){
    var res = 0;
    return {
        init     : function(){ res = 0;},
        getResult: function(){
                debug.log(5, "@@ sumKeeper.getResult: returning: "+res);
                return res;
            },
        work     : function(node){ if (node!==null) res += node;}
    };
}();

maxPicker = function(){
    var res = null;
    return {
        init     : function(){ res = null;},
        getResult: function(){
                debug.log(5, "@@ maxPicker.getResult: returning: "+res);
                return res;
            },
        work     : function(node){
            if (res === null){ res = node;}
            else if (node!==null && node > res){ res = node;}
        }
    };    
}();

minPicker = function(){
    var res = null;
    return {
        init     : function(){ res = null;},
        getResult: function(){
                debug.log(5, "@@ minPicker.getResult: returning: ");
                debug.log(5, res);
                return res;
            },
        work     : function(node){
            if (res === null && node !== null){ res = node;}
            else if (node!==null &&
                node.val !==undefined &&
                node.val < res.val){ res = node; }
            else if (node!==null && node < res){ res = node;}
        }
    };  
}();

// find k-th smallest number in n sorted arrays;
// need to consider the case where some of the subarrays are taken out of the selection;
function kth_n(a, ae, k, h, l){
    var n = ae.length;
    debug.log(2, "------**  kth_n()  **-------");
    debug.log(2, "n: " +n+", k: " + k);
    debug.log(2, "ae: ["+ae+"],  len: "+ae.length);
    debug.log(2, "h: [" + h + "]");
    debug.log(2, "l: [" + l + "]");

    for (var i=0; i<n; i++){
        if (h[ae[i]]-l[ae[i]]+1>k) h[ae[i]]=l[ae[i]]+k-1;
    }
    debug.log(3, "--after reduction --");
    debug.log(3, "h: [" + h + "]");
    debug.log(3, "l: [" + l + "]");

    if (n === 1)
        return a[ae[0]][k-1]; 
    if (k === 1)
        return traverse_at(a, ae, h, l, k, "l", minPicker);
    if (k === traverse_at(a, ae, h, l, k, "s", sumKeeper))
        return traverse_at(a, ae, h, l, k, "h", maxPicker);

    var kn = traverse_at(a, ae, h, l, k, "k", minPicker);
    debug.log(3, "kn: ");
    debug.log(3, kn);

    var idx = kn.idx;
    debug.log(3, "last: k: "+k+", l["+kn.idx+"]: "+l[idx]);
    k -= kn.pos - l[idx] + 1;
    l[idx] = kn.pos + 1;
    debug.log(3, "next: "+"k: "+k+", l["+kn.idx+"]: "+l[idx]);
    if (h[idx]<l[idx]){ // all elements in a[idx] selected;
        //remove a[idx] from the arrays.
        debug.log(4, "All elements selected in a["+idx+"].");
        debug.log(5, "last ae: ["+ae+"]");
        ae.splice(ae.indexOf(idx), 1);
        h[idx] = l[idx] = "_"; // For display purpose only.
        debug.log(5, "next ae: ["+ae+"]");
    }

    return kth_n(a, ae, k, h, l);
}

function find_kth_in_arrays(a, k){

    if (!a || a.length<1 || k<1) throw "Mission Impossible!";

    var ae=[], h=[], l=[], n=0, s, ts=0;
    for (var i=0; i<a.length; i++){
        s = a[i] && a[i].length;
        if (s>0){
            ae.push(i); h.push(s-1); l.push(0);
            ts+=s;
        }
    }

    if (k>ts) throw "Too few elements to choose from!";

    return kth_n(a, ae, k, h, l);
}

/////////////////////////////////////////////////////
// tests
// To show everything: use 6.
debug.setLevel(1);

var a = [2, 3, 5, 7, 89, 223, 225, 667];
var b = [323, 555, 655, 673];
//var b = [99];
var c = [];

debug.log(1, "a = (len: " + a.length + ")");
debug.log(1, a);
debug.log(1, "b = (len: " + b.length + ")");
debug.log(1, b);

for (var k=1; k<a.length+b.length+1; k++){
    debug.log(1, "================== k: " + k + "=====================");

    if (k_largest(a, b, c, k) === 0 ){
      debug.log(1, "c = (len: "+c.length+")");
      debug.log(1, c);
    }

    try{
        result = kth(a, b, k, -1);
        debug.log(1, "===== The " + k + "-th largest number: " + result);
    } catch (e) {
        debug.log(0, "Error message from kth(): " + e);
    }
    debug.log("==================================================");
}

debug.log(1, "################# Now for the n sorted arrays ######################");
debug.log(1, "####################################################################");

x = [[1, 3, 5, 7, 9],
     [-2, 4, 6, 8, 10, 12],
     [8, 20, 33, 212, 310, 311, 623],
     [8],
     [0, 100, 700],
     [300],
     [],
     null];

debug.log(1, "x = (len: "+x.length+")");
debug.log(1, x);

for (var i=0, num=0; i<x.length; i++){
    if (x[i]!== null) num += x[i].length;
}
debug.log(1, "totoal number of elements: "+num);

// to test k in specific ranges:
var start = 0, end = 25;
for (k=start; k<end; k++){
    debug.log(1, "=========================== k: " + k + "===========================");

    try{
        result = find_kth_in_arrays(x, k);
        debug.log(1, "====== The " + k + "-th smallest number: " + result);
    } catch (e) {
        debug.log(1, "Error message from find_kth_in_arrays: " + e);
    }
    debug.log(1, "=================================================================");
}
debug.log(1, "x = (len: "+x.length+")");
debug.log(1, x);
debug.log(1, "totoal number of elements: "+num);

डिबग बर्तनों के साथ पूरा कोड यहां पाया जा सकता है: https://github.com/brainclone/teasers/tree/master/kth


3

यहां मेरा कोड जूल्स ओलीन के समाधान पर आधारित है:

int getNth(vector<int>& v1, vector<int>& v2, int n)
{
    int step = n / 4;

    int i1 = n / 2;
    int i2 = n - i1;

    while(!(v2[i2] >= v1[i1 - 1] && v1[i1] > v2[i2 - 1]))
    {                   
        if (v1[i1 - 1] >= v2[i2 - 1])
        {
            i1 -= step;
            i2 += step;
        }
        else
        {
            i1 += step;
            i2 -= step;
        }

        step /= 2;
        if (!step) step = 1;
    }

    if (v1[i1 - 1] >= v2[i2 - 1])
        return v1[i1 - 1];
    else
        return v2[i2 - 1];
}

int main()  
{  
    int a1[] = {1,2,3,4,5,6,7,8,9};
    int a2[] = {4,6,8,10,12};

    //int a1[] = {1,2,3,4,5,6,7,8,9};
    //int a2[] = {4,6,8,10,12};

    //int a1[] = {1,7,9,10,30};
    //int a2[] = {3,5,8,11};
    vector<int> v1(a1, a1+9);
    vector<int> v2(a2, a2+5);


    cout << getNth(v1, v2, 5);
    return 0;  
}  

1
यह कुछ मामलों के लिए काम नहीं करेगा। उदाहरण के लिए, int a2 [] = {1,2,3,4, 5}; int a1 [] = {5,6,8,10,12}; getNth (a1, a2, 7)। सरणी का सूचकांक सीमा से बाहर चला जाएगा।
जे

2

यहाँ C में मेरा कार्यान्वयन है, आप @Jules Olléon के एल्गोरिथ्म के लिए बताते हैं: एल्गोरिथम के पीछे विचार यह है कि हम i + j = k को बनाए रखते हैं, और ऐसे i और j पाते हैं जिससे कि [i-1] <b [j-1] <[i] (या दूसरा तरीका गोल)। अब चूँकि मैं 'a' में 'b' से छोटा [j-1], और j-1 में 'b' से छोटा [j-1], b [j-1] i + j-1 के तत्व हैं। + 1 = kth सबसे छोटा तत्व। इस तरह के i को खोजने के लिए, j एल्गोरिथ्म सरणियों पर एक द्विध्रुवीय खोज करता है।

int find_k(int A[], int m, int B[], int n, int k) {
   if (m <= 0 )return B[k-1];
   else if (n <= 0) return A[k-1];
   int i =  ( m/double (m + n))  * (k-1);
   if (i < m-1 && i<k-1) ++i;
   int j = k - 1 - i;

   int Ai_1 = (i > 0) ? A[i-1] : INT_MIN, Ai = (i<m)?A[i]:INT_MAX;
   int Bj_1 = (j > 0) ? B[j-1] : INT_MIN, Bj = (j<n)?B[j]:INT_MAX;
   if (Ai >= Bj_1 && Ai <= Bj) {
       return Ai;
   } else if (Bj >= Ai_1 && Bj <= Ai) {
       return Bj;
   }
   if (Ai < Bj_1) { // the answer can't be within A[0,...,i]
       return find_k(A+i+1, m-i-1, B, n, j);
   } else { // the answer can't be within A[0,...,i]
       return find_k(A, m, B+j+1, n-j-1, i);
   }
 }

2

यहाँ मेरा समाधान है। C ++ कोड kth के सबसे छोटे मान के साथ-साथ पुनरावृत्तियों की संख्या को एक लूप का उपयोग करके kth के सबसे छोटे मान को प्राप्त करता है, जो कि मेरी राय में लॉग (k) के क्रम में है। हालांकि कोड को पहले सरणी की लंबाई से छोटा होना चाहिए जो एक सीमा है।

#include <iostream>
#include <vector>
#include<math.h>
using namespace std;

template<typename comparable>
comparable kthSmallest(vector<comparable> & a, vector<comparable> & b, int k){

int idx1; // Index in the first array a
int idx2; // Index in the second array b
comparable maxVal, minValPlus;
float iter = k;
int numIterations = 0;

if(k > a.size()){ // Checks if k is larger than the size of first array
    cout << " k is larger than the first array" << endl;
    return -1;
}
else{ // If all conditions are satisfied, initialize the indexes
    idx1 = k - 1;
    idx2 = -1;
}

for ( ; ; ){
    numIterations ++;
    if(idx2 == -1 || b[idx2] <= a[idx1] ){
        maxVal = a[idx1];
        minValPlus = b[idx2 + 1];
        idx1 = idx1 - ceil(iter/2); // Binary search
        idx2 = k - idx1 - 2; // Ensures sum of indices  = k - 2
    }
    else{
        maxVal = b[idx2];
        minValPlus = a[idx1 + 1];
        idx2 = idx2 - ceil(iter/2); // Binary search
        idx1 = k - idx2 - 2; // Ensures sum of indices  = k - 2
    }
    if(minValPlus >= maxVal){ // Check if kth smallest value has been found
        cout << "The number of iterations to find the " << k << "(th) smallest value is    " << numIterations << endl;
        return maxVal;

    }
    else
        iter/=2; // Reduce search space of binary search
   }
}

int main(){
//Test Cases
    vector<int> a = {2, 4, 9, 15, 22, 34, 45, 55, 62, 67, 78, 85};
    vector<int> b = {1, 3, 6, 8, 11, 13, 15, 20, 56, 67, 89};
    // Input k < a.size()
    int kthSmallestVal;
    for (int k = 1; k <= a.size() ; k++){
        kthSmallestVal = kthSmallest<int>( a ,b ,k );
        cout << k <<" (th) smallest Value is " << kthSmallestVal << endl << endl << endl;
    }
}

1

ऊपर दिया गया पहला छद्म कोड, कई मूल्यों के लिए काम नहीं करता है। उदाहरण के लिए, यहाँ दो ऐरे हैं। int [] a = {१, ५, ६, {, ९, ११, १५, १ {, १ ९}; int [] बी = {४, {, {, १३, १५, १ {, २०, २४, २६};

इसमें k = 3 और k = 9 के लिए काम नहीं किया गया। मेरे पास एक और उपाय है। यह नीचे दिया गया है।

private static void traverse(int pt, int len) {
int temp = 0;

if (len == 1) {
    int val = 0;
    while (k - (pt + 1) - 1 > -1 && M[pt] < N[k - (pt + 1) - 1]) {

    if (val == 0)
        val = M[pt] < N[k - (pt + 1) - 1] ? N[k - (pt + 1) - 1]
            : M[pt];
    else {
        int t = M[pt] < N[k - (pt + 1) - 1] ? N[k - (pt + 1) - 1]
            : M[pt];
        val = val < t ? val : t;

    }

    ++pt;
    }

    if (val == 0)
    val = M[pt] < N[k - (pt + 1) - 1] ? N[k - (pt + 1) - 1] : M[pt];

    System.out.println(val);
    return;
}

temp = len / 2;

if (M[pt + temp - 1] < N[k - (pt + temp) - 1]) {
    traverse(pt + temp, temp);

} else {
    traverse(pt, temp);
}

}

लेकिन ... यह k = 5 के लिए भी काम नहीं कर रहा है। K की यह सम / विषम पकड़ है जो इसे सरल नहीं होने दे रही है।


1
public class KthSmallestInSortedArray {

    public static void main(String[] args) {
        int a1[] = {2, 3, 10, 11, 43, 56},
                a2[] = {120, 13, 14, 24, 34, 36},
                k = 4;

        System.out.println(findKthElement(a1, a2, k));

    }

    private static int findKthElement(int a1[], int a2[], int k) {

        /** Checking k must less than sum of length of both array **/
        if (a1.length + a2.length < k) {
            throw new IllegalArgumentException();
        }

        /** K must be greater than zero **/
        if (k <= 0) {
            throw new IllegalArgumentException();
        }

        /**
         * Finding begin, l and end such that
         * begin <= l < end
         * a1[0].....a1[l-1] and
         * a2[0]....a2[k-l-1] are the smallest k numbers
         */
        int begin = Math.max(0, k - a2.length);
        int end = Math.min(a1.length, k);

        while (begin < end) {
            int l = begin + (end - begin) / 2;

            /** Can we include a1[l] in the k smallest numbers */
            if ((l < a1.length) &&
                    (k - l > 0) &&
                    (a1[l] < a2[k - l - 1])) {

                begin = l + 1;

            } else if ((l > 0) &&
                    (k - l < a2.length) &&
                    (a1[l - 1] > a2[k - 1])) {

                /**
                 * This is the case where we can discard
                 * a[l-1] from the set of k smallest numbers
                 */
                end = l;

            } else {

                /**
                 * We found our answer since both inequalities were
                 * false
                 */
                begin = l;
                break;
            }
        }

        if (begin == 0) {
            return a2[k - 1];
        } else if (begin == k) {
            return a1[k - 1];
        } else {
            return Math.max(a1[begin - 1], a2[k - begin - 1]);
        }
    }
}

1

यहाँ जावा में मेरा समाधान है। इसे और बेहतर बनाने की कोशिश करेंगे

  public class FindKLargestTwoSortedArray {

    public static void main(String[] args) {
        int[] arr1 = { 10, 20, 40, 80 };
        int[] arr2 = { 15, 35, 50, 75 };

    FindKLargestTwoSortedArray(arr1, 0, arr1.length - 1, arr2, 0,
            arr2.length - 1, 6);
    }


    public static void FindKLargestTwoSortedArray(int[] arr1, int start1,
            int end1, int[] arr2, int start2, int end2, int k) {

        if ((start1 <= end1 && start1 >= 0 && end1 < arr1.length)
                && (start2 <= end2 && start2 >= 0 && end2 < arr2.length)) {

            int midIndex1 = (start1 + (k - 1) / 2);
            midIndex1 = midIndex1 >= arr1.length ? arr1.length - 1 : midIndex1;
            int midIndex2 = (start2 + (k - 1) / 2);
            midIndex2 = midIndex2 >= arr2.length ? arr2.length - 1 : midIndex2;


            if (arr1[midIndex1] == arr2[midIndex2]) {
                System.out.println("element is " + arr1[midIndex1]);
            } else if (arr1[midIndex1] < arr2[midIndex2]) {

                if (k == 1) {
                    System.out.println("element is " + arr1[midIndex1]);
                    return;
                } else if (k == 2) {
                    System.out.println("element is " + arr2[midIndex2]);
                    return;
                }else if (midIndex1 == arr1.length-1 || midIndex2 == arr2.length-1 ) {
                    if(k==(arr1.length+arr2.length)){
                    System.out.println("element is " + arr2[midIndex2]);
                    return;
                    }else if(k==(arr1.length+arr2.length)-1){
                        System.out.println("element is " + arr1[midIndex1]);
                        return;
                    }

                }

                int remainingElementToSearch = k - (midIndex1-start1);
                FindKLargestTwoSortedArray(
                        arr1,
                        midIndex1,
                        (midIndex1 + remainingElementToSearch) >= arr1.length ? arr1.length-1
                                : (midIndex1 + remainingElementToSearch), arr2,
                        start2, midIndex2, remainingElementToSearch);

            } else if (arr1[midIndex1] > arr2[midIndex2]) {
                FindKLargestTwoSortedArray(arr2, start2, end2, arr1, start1,
                        end1, k);
            }

        } else {
            return;
        }

    }
}

यह एल्गो से अद्भुत यूट्यूब वीडियो से प्रेरित है


1

कोड से लिंक करें जटिलता (लॉग (n) + लॉग (एम))

कोड से लिंक करें (लॉग (n) * लॉग (एम))

कार्यान्वयन(लॉग (n) + लॉग (m)) समाधान का

मैं समस्या के बारे में अपनी व्याख्या जोड़ना चाहूंगा। यह एक क्लासिक समस्या है जहां हमें इस तथ्य का उपयोग करना होगा कि दो सरणियों को क्रमबद्ध किया गया है। हमें आकार sz1 के दो क्रमबद्ध सरणियों और आकार sz2 के arr2 दिए गए हैं

क) यदि मान लिया जाए

यदि k मान्य है तो जाँच करना

k है> (sz1 + sz2)

तब हम दोनों प्रकार के सरणियों के संघ में kth सबसे छोटा तत्व नहीं खोज सकते हैं। तो अमान्य डेटा वापस लौटाएं। बी) अब यदि उपरोक्त शर्त गलत है और हमारे पास कश्मीर का वैध और व्यवहार्य मूल्य है,

एज के मामलों का प्रबंधन

हम अंत में + के + इनफिनिटी वैल्यूज के साथ-साथ k = 1,2 और k = (sz1 + sz2-1), (sz1 + sz2) आदि के दोनों मामलों को जोड़ेंगे।

अब दोनों सरणियों का आकार क्रमशः (sz1 + 2) और (sz2 + 2) है

मुख्य एल्गोरिथ्म

अब, हम arr1 पर बाइनरी खोज करेंगे। हम बाइनरी 1 पर बाइनरी खोज करेंगे I startIndex <= i <= endIndex की

ऐसा है कि अगर हम constrint {(i + j) = k} का उपयोग करके arr2 में संबंधित इंडेक्स j पाते हैं, तो यदि

if (arr2 [j-1] <arr1 [i] <arr2 [j]) , तो arr1 [i] kth सबसे छोटा (Case 1) है

अगर और (arr1 [i-1] <arr2 [j] <arr1 [i]) , तो arr2 [i] kth सबसे छोटा (केस 2) है

बाकी या तो arr1 को दर्शाता है [i] <arr2 [j-1] <arr2 [j] (Case3)

or arr2 [j-1] <arr2 [j] <arr1 [i] (Case4)

चूँकि हम जानते हैं कि kth के सबसे छोटे तत्व (k-1) में दोनों सरणियों के संघात की तुलना में छोटे तत्व होते हैं ? इसलिए,

केस 1 में , हम क्या किया है, हम यह सुनिश्चित किया (k-1) छोटे तत्वों की कुल arr1 को देखते हैं कि [i] क्योंकि तत्वों arr1 [i] में arr1 सरणी i-1 संख्या की तुलना में हम जानते हैं (arr2 हैं [से छोटा j-1] <arr1 [i] <arr2 [j]) और arr2 [i] से छोटे तत्वों की संख्या j-1 है क्योंकि j का उपयोग करते हुए पाया जाता है (i-1) + (j-1) = (k -1) तो kth सबसे छोटा तत्व एरियर 1 होगा [i]

लेकिन उत्तर हमेशा पहली सरणी से नहीं आ सकता है अर्थात arr1 तो हमने case2 के लिए जाँच की जो कि केस 1 की तरह ही संतुष्ट करता है क्योंकि (i-1) + (j-1) = (k-1)। अब यदि हमारे पास (arr1 [i-1] <arr2 [j] <arr1 [i]) है, तो हमारे पास दोनों k सरणियों के संघटन में arr2 [j] की तुलना में कुल k-1 तत्व हैं, इसलिए इसका kth सबसे छोटा तत्व है।

में case3 , मामले 1 या मामले 2 में से किसी को यह फार्म का, हम मैं बढ़ाने के लिए और जे बाधा का उपयोग कर अनुसार मिल जाएगा जरूरत {(i + जे) = k} सही भाग को द्विआधारी खोज चाल में यानी यानी बनाने STARTINDEX = middleIndex

में case4 , मामले 1 या मामले 2 में से किसी को यह फार्म का, हम मैं घटती करने के लिए और जे {(i + जे) = k} बाधा बाएं हिस्से को द्विआधारी खोज चाल में यानी यानी बनाने ENDINDEX = middleIndex का उपयोग कर अनुसार मिल जाएगा जरूरत ।

अब startIndex और endIndex को कैसे तय किया जाए, start1ex = 1 और endIndex = ?? के साथ arr1 पर बाइनरी सर्च की शुरुआत में। हमें तय करने की आवश्यकता है।

यदि k> sz1, endIndex = (sz1 + 1), अन्यथा endIndex = k;

क्योंकि यदि k पहले सरणी के आकार से अधिक है, तो हमें पूरे सरणी arr1 पर बाइनरी खोज करनी पड़ सकती है, अन्यथा हमें केवल इसके पहले तत्वों को लेने की आवश्यकता है क्योंकि sz1-k तत्व कभी भी kth सबसे छोटी गणना में योगदान नहीं दे सकते हैं।

कोड नीचे दिखाया गया है

// Complexity    O(log(n)+log(m))

#include<bits/stdc++.h>
using namespace std;
#define f(i,x,y) for(int i = (x);i < (y);++i)
#define F(i,x,y) for(int i = (x);i > (y);--i)
int max(int a,int b){return (a > b?a:b);}
int min(int a,int b){return (a < b?a:b);}
int mod(int a){return (a > 0?a:((-1)*(a)));}
#define INF 1000000




int func(int *arr1,int *arr2,int sz1,int sz2,int k)

{

if((k <= (sz1+sz2))&&(k > 0))

{
int s = 1,e,i,j;
if(k > sz1)e = sz1+1;
else e = k;
while((e-s)>1)
{
  i = (e+s)/2;
  j = ((k-1)-(i-1)); 
  j++;
  if(j > (sz2+1)){s = i;}
  else if((arr1[i] >= arr2[j-1])&&(arr1[i] <= arr2[j]))return arr1[i];
  else if((arr2[j] >= arr1[i-1])&&(arr2[j] <= arr1[i]))return arr2[j];
  else if(arr1[i] < arr2[j-1]){s = i;}
  else if(arr1[i] > arr2[j]){e = i;}
  else {;}
}
i = e,j = ((k-1)-(i-1));j++;
if((arr1[i] >= arr2[j-1])&&(arr1[i] <= arr2[j]))return arr1[i];
else if((arr2[j] >= arr1[i-1])&&(arr2[j] <= arr1[i]))return arr2[j];
else
{
  i = s,j = ((k-1)-(i-1));j++;
  if((arr1[i] >= arr2[j-1])&&(arr1[i] <= arr2[j]))return arr1[i];
  else return arr2[j];
}

  }

 else

{
cout << "Data Invalid" << endl;
return -INF;

}

}





int main()

{
int n,m,k;
cin >> n >> m >> k;
int arr1[n+2];
int arr2[m+2];
f(i,1,n+1)
cin >> arr1[i];
f(i,1,m+1)
cin >> arr2[i];
arr1[0] = -INF;
arr2[0] = -INF;
  arr1[n+1] = +INF;  
arr2[m+1] = +INF; 
int val = func(arr1,arr2,n,m,k);
if(val != -INF)cout << val << endl;   
return 0;

}

जटिलता के समाधान के लिए (लॉग (एन) * लॉग (एम))

बस मैं इस तथ्य का लाभ उठाने से चूक गया कि प्रत्येक i के लिए j को बाधा {(i-1) + (j-1) = (k-1)} का उपयोग करके पाया जा सकता है, इसलिए प्रत्येक ii के लिए दूसरे सरणी पर द्विआधारी खोज को लागू करना था। j को खोजने के लिए ऐसा करें कि arr2 [j] <= arr1 [i]। इस समाधान को आगे भी अनुकूलित किया जा सकता है


1

मूल रूप से, इस दृष्टिकोण के माध्यम से आप प्रत्येक चरण पर के / 2 तत्वों को त्याग सकते हैं। K, k => k / 2 => k / 4 => ... से पुन: बदल जाएगा। जब तक यह 1. तक नहीं पहुंच जाता है , तब तक Time Complexity O (logk) है

K = 1 पर, हमें दो सरणियों में सबसे कम मिलता है।

निम्नलिखित कोड जावा में है। कृपया ध्यान दें कि हम इंडेक्स से कोड में 1 (-1) घटा रहे हैं क्योंकि जावा सरणी का इंडेक्स 0 से शुरू होता है और 1 से नहीं, उदाहरण के लिए। k = 3 को किसी सरणी के 2 सूचकांक में तत्व द्वारा दर्शाया गया है।

private int kthElement(int[] arr1, int[] arr2, int k) {
        if (k < 1 || k > (arr1.length + arr2.length))
            return -1;
        return helper(arr1, 0, arr1.length - 1, arr2, 0, arr2.length - 1, k);
    }


private int helper(int[] arr1, int low1, int high1, int[] arr2, int low2, int high2, int k) {
    if (low1 > high1) {
        return arr2[low2 + k - 1];
    } else if (low2 > high2) {
        return arr1[low1 + k - 1];
    }
    if (k == 1) {
        return Math.min(arr1[low1], arr2[low2]);
    }
    int i = Math.min(low1 + k / 2, high1 + 1);
    int j = Math.min(low2 + k / 2, high2 + 1);
    if (arr1[i - 1] > arr2[j - 1]) {
        return helper(arr1, low1, high1, arr2, j, high2, k - (j - low2));
    } else {
        return helper(arr1, i, high1, arr2, low2, high2, k - (i - low1));
    }
}

1
#include <bits/stdc++.h>
using namespace std;

int findKthElement(int a[],int start1,int end1,int b[],int start2,int end2,int k){

    if(start1 >= end1)return b[start2+k-1];
    if(start2 >= end2)return a[start1+k-1];
    if(k==1)return min(a[start1],b[start2]);
    int aMax = INT_MAX;
    int bMax = INT_MAX;
    if(start1+k/2-1 < end1) aMax = a[start1 + k/2 - 1];
    if(start2+k/2-1 < end2) bMax = b[start2 + k/2 - 1];

    if(aMax > bMax){
        return findKthElement(a,start1,end1,b,start2+k/2,end2,k-k/2);
    }
    else{
        return findKthElement(a,start1 + k/2,end1,b,start2,end2,k-k/2);
    }
}

int main(void){
    int t;
    scanf("%d",&t);
    while(t--){
        int n,m,k;
        cout<<"Enter the size of 1st Array"<<endl;
        cin>>n;
        int arr[n];
        cout<<"Enter the Element of 1st Array"<<endl;
        for(int i = 0;i<n;i++){
            cin>>arr[i];
        }
        cout<<"Enter the size of 2nd Array"<<endl;
        cin>>m;
        int arr1[m];
        cout<<"Enter the Element of 2nd Array"<<endl;
        for(int i = 0;i<m;i++){
            cin>>arr1[i];
        }
        cout<<"Enter The Value of K";
        cin>>k;
        sort(arr,arr+n);
        sort(arr1,arr1+m);
        cout<<findKthElement(arr,0,n,arr1,0,m,k)<<endl;
    }

    return 0;
}

समय जटिलता हे (लॉग (मिनट (n, m)) है)


1

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

    public static int kth_two_sorted(int []a, int b[],int k){
    if(a.length > b.length){
        return kth_two_sorted(b,a,k);
    }
    if(a.length + a.length < k){
        throw new RuntimeException("wrong argument");
    }
    int low = 0;
    int high = k;
    if(a.length <= k){
        high = a.length-1;
    }
    while(low <= high){
        int sizeA = low+(high - low)/2;
        int sizeB = k - sizeA;
        boolean shrinkLeft = false;
        boolean extendRight = false;
        if(sizeA != 0){
            if(sizeB !=b.length){
                if(a[sizeA-1] > b[sizeB]){
                    shrinkLeft = true;
                    high = sizeA-1;
                }
            }
        }
        if(sizeA!=a.length){
            if(sizeB!=0){
                if(a[sizeA] < b[sizeB-1]){
                    extendRight = true;
                    low = sizeA;
                }
            }
        }
        if(!shrinkLeft && !extendRight){
            return Math.max(a[sizeA-1],b[sizeB-1]) ;
        }
    }
    throw  new IllegalArgumentException("we can't be here");
}

हमारे पास [low, high]सरणी के लिए एक सीमा है aऔर हम इस सीमा को संकीर्ण कर देते हैं क्योंकि हम एल्गोरिथम के माध्यम से आगे बढ़ते हैं। sizeAशो कैसे से आइटम के कई kआइटम सरणी से कर रहे हैं aऔर इसके बारे में मूल्य से निकला है lowऔर highsizeBको छोड़कर हम मूल्य इस तरह से कि गणना एक ही परिभाषा है sizeA+sizeB=k। उन दो सीमाओं पर मूल्यों के आधार पर निष्कर्ष निकालते हैं कि हमें सरणी में दाईं ओर का विस्तार करना है aया बाईं ओर सिकुड़ना है। अगर हम एक ही स्थिति में फंस इसका मतलब है कि हम समाधान मिल गया और हम की स्थिति में मूल्यों की अधिकतम वापस आ जाएगी sizeA-1से aऔर sizeB-1से b


0

इस कोड की जाँच करें।

import math
def findkthsmallest():

    A=[1,5,10,22,30,35,75,125,150,175,200]
    B=[15,16,20,22,25,30,100,155,160,170]
    lM=0
    lN=0
    hM=len(A)-1
    hN=len(B)-1
    k=17

    while True:
        if k==1:
            return min(A[lM],B[lN])


        cM=hM-lM+1
        cN=hN-lN+1
        tmp = cM/float(cM+cN)
        iM=int(math.ceil(tmp*k))
        iN=k-iM
        iM=lM+iM-1
        iN=lN+iN-1
        if A[iM] >= B[iN]:
            if iN == hN or A[iM] < B[iN+1]:
                return A[iM]
            else:
                k = k - (iN-lN+1)
                lN=iN+1
                hM=iM-1
        if B[iN] >= A[iM]:
            if iM == hM or B[iN] < A[iM+1]:
                return B[iN]
            else:
                k = k - (iM-lM+1)
                lM=iM+1
                hN=iN-1
        if hM < lM:
            return B[lN+k-1]
        if hN < lN:
            return A[lM+k-1]

if __name__ == '__main__':
    print findkthsmallest();

स्पष्टीकरण प्रदान करें
अभिजीत सरकार

0

दो क्रमबद्ध एरे के संघ में k-वें लघु तत्व को खोजने के लिए C # कोड के नीचे। समय जटिलता: हे (लॉग)

        public static int findKthSmallestElement1(int[] A, int startA, int endA, int[] B, int startB, int endB, int k)
        {
            int n = endA - startA;
            int m = endB - startB;

            if (n <= 0)
                return B[startB + k - 1];
            if (m <= 0)
                return A[startA + k - 1];
            if (k == 1)
                return A[startA] < B[startB] ? A[startA] : B[startB];

            int midA = (startA + endA) / 2;
            int midB = (startB + endB) / 2;

            if (A[midA] <= B[midB])
            {
                if (n / 2 + m / 2 + 1 >= k)
                    return findKthSmallestElement1(A, startA, endA, B, startB, midB, k);
                else
                    return findKthSmallestElement1(A, midA + 1, endA, B, startB, endB, k - n / 2 - 1);
            }
            else
            {
                if (n / 2 + m / 2 + 1 >= k)
                    return findKthSmallestElement1(A, startA, midA, B, startB, endB, k);
                else
                    return findKthSmallestElement1(A, startA, endA, B, midB + 1, endB, k - m / 2 - 1);

            }
        }

कोई बग नहीं है, मैंने
पीयूष पटेल

1
धन्यवाद sammy333, मैंने कोड अपडेट कर दिया है। अब इसका काम कर रहा है
पियूष पटेल

( अगर midAसे गणना न करें। लघु सरणियों के लिए जाँच करें, साथ शुरू ।)endAk < nreturn B[startB + k - 1];
ग्रेबर्ड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.