मैं एक 2d सरणी में एक नंबर की खोज कैसे कर सकता हूं जो बाएं से दाएं और ऊपर से नीचे तक छांटा गया है?


90

मुझे हाल ही में यह साक्षात्कार प्रश्न दिया गया था और मैं उत्सुक हूं कि इसका एक अच्छा समाधान क्या होगा।

मान लीजिए कि मुझे एक 2d सरणी दी गई है, जहां सरणी के सभी नंबर बाएं से दाएं और ऊपर से नीचे तक बढ़ते क्रम में हैं।

यदि लक्ष्य संख्या सरणी में है, तो खोज और निर्धारित करने का सबसे अच्छा तरीका क्या है?

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

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

किसी को भी इस समस्या को हल करने पर कोई अच्छा विचार है?

उदाहरण सरणी:

बाएं से दाएं क्रमबद्ध, ऊपर से नीचे।

1  2  4  5  6  
2  3  5  7  8  
4  6  8  9  10  
5  8  9  10 11  

सरल प्रश्न: क्या ऐसा हो सकता है कि आपके पास एक ही मूल्य वाला पड़ोसी हो सकता है [[1 1][1 1]]:?
मैथ्यू एम।

जवाबों:


115

यहाँ एक सरल तरीका है:

  1. नीचे-बाएँ कोने से शुरू करें।
  2. यदि लक्ष्य उस मूल्य से कम है, तो यह हमारे ऊपर होना चाहिए, इसलिए एक को ऊपर ले जाएं
  3. अन्यथा हम जानते हैं कि लक्ष्य उस कॉलम में नहीं हो सकता है, इसलिए दाईं ओर जाएं
  4. गोटो २।

एक NxMसरणी के लिए, यह अंदर चलता है O(N+M)। मुझे लगता है कि बेहतर करना मुश्किल होगा। :)


संपादित करें: अच्छी चर्चा के बहुत सारे। मैं ऊपर सामान्य मामले के बारे में बात कर रहा था; स्पष्ट रूप से, अगर Nया M छोटे हैं, आप एक द्विआधारी खोज दृष्टिकोण का उपयोग कुछ लघुगणक समय निकट में यह करने के लिए कर सकता है।

यहाँ कुछ विवरण हैं, जो उत्सुक हैं:

इतिहास

इस सरल एल्गोरिथ्म को एक सैडलबैक खोज कहा जाता है । यह थोड़ी देर के लिए चारों ओर है, और यह इष्टतम है जब N == M। कुछ संदर्भ:

हालांकि, जब N < M, अंतर्ज्ञान से पता चलता है कि द्विआधारी खोज से बेहतर करने में सक्षम होना चाहिए O(N+M): उदाहरण के लिए, जब N == 1, एक शुद्ध द्विआधारी खोज रैखिक समय के बजाय लघुगणक में चलेगा।

सबसे खराब मामला

रिचर्ड बर्ड ने इस अंतर्ज्ञान की जांच की कि द्विआधारी खोज 2006 के पेपर में सैडलबैक एल्गोरिथ्म में सुधार कर सकती है:

एक असामान्य रूप से संवादी तकनीक का उपयोग करते हुए, बर्ड हमें दिखाता है कि इसके लिए N <= M, इस समस्या की एक कम सीमा है Ω(N * log(M/N))। यह बाध्य समझ में आता है, क्योंकि यह हमें रैखिक प्रदर्शन देता है जब N == Mऔर लघुगणक प्रदर्शन जब N == 1

आयताकार सरणियों के लिए एल्गोरिदम

पंक्ति-दर-पंक्ति बाइनरी खोज का उपयोग करने वाला एक दृष्टिकोण इस तरह दिखता है:

  1. आयताकार सरणी से शुरू करें जहां N < M। मान लें कि Nपंक्तियाँ हैं और Mस्तंभ हैं।
  2. के लिए मध्य पंक्ति पर एक द्विआधारी खोज करें value। यदि हम इसे ढूंढते हैं, तो हम कर रहे हैं
  3. अन्यथा हमने संख्याओं का एक आसन्न जोड़ा sऔर g, जहाँ पाया है s < value < g
  4. ऊपर और बाईं ओर संख्याओं की आयत की तुलना sमें कम है value, इसलिए हम इसे समाप्त कर सकते हैं।
  5. नीचे और नीचे की आयत gसे अधिक है value, इसलिए हम इसे समाप्त कर सकते हैं।
  6. शेष दो आयतों में से प्रत्येक के लिए चरण (2) पर जाएँ।

सबसे खराब स्थिति के संदर्भ में, यह एल्गोरिथ्म log(M)आधे संभव समाधानों को खत्म करने का काम करता है , और फिर दो छोटी समस्याओं पर दो बार पुन: कॉल करता है। हमें log(M)हर पंक्ति के लिए उस कार्य का एक छोटा संस्करण दोहराना होगा , लेकिन यदि स्तंभों की संख्या की तुलना में पंक्तियों की संख्या छोटी है, तो लॉगरिदमिक समय में उन सभी स्तंभों को समाप्त करने में सक्षम होना सार्थक होने लगता है

यह एल्गोरिथ्म की एक जटिलता देता है T(N,M) = log(M) + 2 * T(M/2, N/2), जो बर्ड दिखाता है O(N * log(M/N))

क्रेग गिदनी द्वारा पोस्ट किया गया एक और दृष्टिकोण ऊपर दिए गए दृष्टिकोण के समान एक एल्गोरिथ्म का वर्णन करता है: यह एक कदम आकार का उपयोग करके एक समय में एक पंक्ति की जांच करता है M/N। उनके विश्लेषण से पता चलता है कि इससे O(N * log(M/N))प्रदर्शन में भी सुधार होता है।

प्रदर्शन की तुलना

बिग-ओ विश्लेषण सभी अच्छी तरह से और अच्छा है, लेकिन ये दृष्टिकोण व्यवहार में कितने अच्छे हैं? नीचे दिए गए चार्ट तेजी से "वर्ग" सरणियों के लिए चार एल्गोरिदम की जांच करते हैं:

एल्गोरिथ्म प्रदर्शन बनाम फुहार

("भोली" एल्गोरिथ्म बस सरणी के हर तत्व को खोजता है। "पुनरावर्ती" एल्गोरिथ्म ऊपर वर्णित है। "हाइब्रिड" एल्गोरिथ्म गिडनी के एल्गोरिथ्म का एक कार्यान्वयन है । प्रत्येक सरणी आकार के लिए, प्रत्येक एल्गोरिथ्म को निश्चित सेट पर निर्धारित समय के अनुसार मापा गया था। 1,000,000 बेतरतीब ढंग से उत्पन्न सरणियाँ।)

कुछ उल्लेखनीय बिंदु:

  • जैसा कि अपेक्षित था, "बाइनरी सर्च" एल्गोरिदम आयताकार सरणियों पर सबसे अच्छा प्रदर्शन प्रदान करते हैं और सैडलबैक एल्गोरिथम स्क्वायर किरणों पर सबसे अच्छा काम करता है।
  • सैडलबैक एल्गोरिथ्म 1-डी सरणियों के लिए "भोली" एल्गोरिदम से भी बदतर प्रदर्शन करता है, संभवतः क्योंकि यह प्रत्येक आइटम पर कई तुलना करता है।
  • प्रदर्शन ने हिट किया कि "बाइनरी खोज" एल्गोरिदम स्क्वायर सरणियों पर ले जाते हैं, संभवतः दोहराए गए बाइनरी खोजों को चलाने के ओवरहेड के कारण।

सारांश

द्विआधारी खोज का चतुर उपयोग O(N * log(M/N)आयताकार और वर्ग सरणियों दोनों के लिए प्रदर्शन प्रदान कर सकता है । O(N + M)"Saddleback" एल्गोरिथ्म बहुत सरल है, लेकिन सरणियों के रूप में प्रदर्शन गिरावट से ग्रस्त तेजी से आयताकार हो जाते हैं।


6
विकर्ण चलने के लिए द्विआधारी खोज लागू करें और आपको O (logN) या O (logM) जो भी अधिक हो।
अनुराग

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

1
यदि N = 1 और M = 1000000 i, O (N + M) से बेहतर कर सकते हैं, तो एक और समाधान प्रत्येक पंक्ति में बाइनरी खोज को लागू कर रहा है जो O (N * log (M)) लाता है, जहां N <M होता है कि यह पैदावार छोटा स्थिर।
लूका राहने

1
मैंने आपकी विधि और बाइनरी सर्च विधि दोनों का उपयोग करके कुछ परीक्षण किए और परिणाम यहां पोस्ट किए । लगता है कि ज़िगज़ैग विधि सबसे अच्छी है, जब तक कि मैं दोनों तरीकों के लिए सबसे खराब स्थिति पैदा करने में विफल रहा।
११

1
संदर्भ का अच्छा उपयोग! हालाँकि जब M==Nहम O(N)जटिलता चाहते हैं, तब O(N*log(N/N))से नहीं जब कि बाद वाला शून्य नहीं है। एक सही "एकीकृत" तेज बाउंड O(N*(log(M/N)+1))कब है N<=M
हार्डमैथ

35

इस समस्या में Θ(b lg(t))समय लगता है, जहां b = min(w,h)और t=b/max(w,h)। मैं इस ब्लॉग पोस्ट में समाधान पर चर्चा करता हूं ।

निम्न परिबंध

एक विरोधी Ω(b lg(t))खुद को मुख्य विकर्ण पर सीमित करके प्रश्नों को बनाने के लिए एक एल्गोरिथ्म को मजबूर कर सकता है :

मुख्य विकर्ण का उपयोग करने वाला सलाहकार

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

ध्यान दें कि bआकार की स्वतंत्र सॉर्ट की गई सूची हैं t, जिससे Ω(b lg(t))प्रश्नों को पूरी तरह से समाप्त करने की आवश्यकता होती है ।

कलन विधि

  1. (सामान्यता के नुकसान के बिना मान लें कि w >= h)
  2. tमान्य क्षेत्र के शीर्ष दाएं कोने के बाईं ओर सेल के विरुद्ध लक्ष्य आइटम की तुलना करें
    • यदि सेल का आइटम मेल खाता है, तो वर्तमान स्थिति लौटाएं।
    • यदि सेल का आइटम लक्ष्य आइटम से कम है, तो tबाइनरी खोज के साथ पंक्ति में शेष कोशिकाओं को समाप्त करें। यदि ऐसा करते समय एक मिलान आइटम पाया जाता है, तो इसकी स्थिति के साथ वापस लौटें।
    • अन्यथा सेल का आइटम टारगेट आइटम से अधिक है, tछोटे कॉलम को खत्म करता है ।
  3. यदि कोई वैध क्षेत्र नहीं बचा है, तो विफलता लौटें
  4. गोटो स्टेप 2

एक आइटम ढूँढना:

एक आइटम ढूँढना

एक आइटम का निर्धारण मौजूद नहीं है:

एक आइटम का निर्धारण मौजूद नहीं है

किंवदंती: सफेद कोशिकाएं छोटी वस्तुएं होती हैं, ग्रे कोशिकाएं बड़ी वस्तुएं होती हैं, और हरी कोशिका एक समान वस्तु होती है।

विश्लेषण

b*tसमाप्त करने के लिए छोटे कॉलम हैं । bसमाप्त करने के लिए लंबी पंक्तियाँ हैं । एक लंबी पंक्ति को समाप्त करने में O(lg(t))समय लगता है। tछोटे कॉलम को खत्म करने में O(1)समय लगता है।

सबसे खराब स्थिति में हमें समय लेते हुए हर कॉलम और हर पंक्ति को खत्म करना होगा O(lg(t)*b + b*t*1/t) = O(b lg(t))

ध्यान दें कि मैं lg1 (यानी lg(x) = log_2(max(2,x))) से ऊपर के परिणामों के लिए क्लैम्प मान रहा हूं । इसीलिए जब w=h, अर्थ t=1, हमें अपेक्षित सीमा मिलती है O(b lg(1)) = O(b) = O(w+h)

कोड

public static Tuple<int, int> TryFindItemInSortedMatrix<T>(this IReadOnlyList<IReadOnlyList<T>> grid, T item, IComparer<T> comparer = null) {
    if (grid == null) throw new ArgumentNullException("grid");
    comparer = comparer ?? Comparer<T>.Default;

    // check size
    var width = grid.Count;
    if (width == 0) return null;
    var height = grid[0].Count;
    if (height < width) {
        var result = grid.LazyTranspose().TryFindItemInSortedMatrix(item, comparer);
        if (result == null) return null;
        return Tuple.Create(result.Item2, result.Item1);
    }

    // search
    var minCol = 0;
    var maxRow = height - 1;
    var t = height / width;
    while (minCol < width && maxRow >= 0) {
        // query the item in the minimum column, t above the maximum row
        var luckyRow = Math.Max(maxRow - t, 0);
        var cmpItemVsLucky = comparer.Compare(item, grid[minCol][luckyRow]);
        if (cmpItemVsLucky == 0) return Tuple.Create(minCol, luckyRow);

        // did we eliminate t rows from the bottom?
        if (cmpItemVsLucky < 0) {
            maxRow = luckyRow - 1;
            continue;
        }

        // we eliminated most of the current minimum column
        // spend lg(t) time eliminating rest of column
        var minRowInCol = luckyRow + 1;
        var maxRowInCol = maxRow;
        while (minRowInCol <= maxRowInCol) {
            var mid = minRowInCol + (maxRowInCol - minRowInCol + 1) / 2;
            var cmpItemVsMid = comparer.Compare(item, grid[minCol][mid]);
            if (cmpItemVsMid == 0) return Tuple.Create(minCol, mid);
            if (cmpItemVsMid > 0) {
                minRowInCol = mid + 1;
            } else {
                maxRowInCol = mid - 1;
                maxRow = mid - 1;
            }
        }

        minCol += 1;
    }

    return null;
}

1
मेरे सिर पर दिलचस्प और संभवतः आंशिक रूप से। मैं जटिलता विश्लेषण की इस "प्रतिकूल" शैली से परिचित नहीं हूं। क्या विपक्षी वास्तव में किसी तरह गतिशील रूप से सरणी बदल रहा है जैसा कि आप खोजते हैं, या क्या वह सिर्फ एक नाम है जो दुर्भाग्य से आपको सबसे खराब स्थिति में मिलता है?
११

2
@ The111 बुरा भाग्य किसी बुरे रास्ते को चुनने वाले के बराबर है जो अब तक देखी गई चीजों का उल्लंघन नहीं करता है, इसलिए उन दोनों परिभाषाओं में से एक ही काम करता है। मैं वास्तव में कम्प्यूटेशनल जटिलता के संबंध में विशेष रूप से तकनीक की व्याख्या करने वाले लिंक खोजने में परेशानी महसूस कर रहा हूं ... मुझे लगा कि यह एक बहुत अधिक ज्ञात विचार था।
क्रेग गिदनी

क्योंकि लॉग (1) = 0, के O(b*(lg(t)+1))बजाय जटिलता अनुमान दिया जाना चाहिए O(b*lg(t))। अच्छा लेखन, esp। बाध्य करने के लिए "सबसे खराब स्थिति" दिखाने में "प्रतिकूल तकनीक" पर ध्यान देने के लिए।
हार्डमैथ

@hardmath ने उत्तर में उल्लेख किया है। मैंने इसे थोड़ा स्पष्ट किया।
क्रेग गिदनी

17

मैं इस समस्या के लिए फूट डालो और जीत की रणनीति का उपयोग करेगा, जैसा कि आपने सुझाव दिया था, लेकिन विवरण थोड़ा अलग हैं।

यह मैट्रिक्स के सबरेंज पर एक पुनरावर्ती खोज होगी।

प्रत्येक चरण पर, सीमा के बीच में एक तत्व चुनें। यदि पाया गया वह मूल्य है जो आप मांग रहे हैं, तो आप कर रहे हैं।

अन्यथा, यदि पाया गया मान उस मूल्य से कम है जिसे आप मांग रहे हैं, तो आप जानते हैं कि यह ऊपर के चतुर्थांश में नहीं है और आपकी वर्तमान स्थिति के बाईं ओर है। इसलिए पुनरावर्ती रूप से दो उपग्रहों की खोज करें: वर्तमान स्थिति के नीचे सब कुछ (विशेष रूप से), और सब कुछ (विशेष रूप से) दाईं ओर जो वर्तमान स्थिति में या उससे ऊपर है।

अन्यथा, (पाया गया मूल्य आपके द्वारा मांगे जाने वाले मूल्य से अधिक है) आप जानते हैं कि यह नीचे दिए गए चतुर्थांश में नहीं है और आपकी वर्तमान स्थिति के दाईं ओर है। तो दो सबरंगों की खोज करें: वर्तमान स्थिति के बाईं ओर सब कुछ (विशेष रूप से), और वर्तमान स्थिति के ऊपर सब कुछ (विशेष रूप से) जो वर्तमान कॉलम या दाईं ओर एक कॉलम है।

और बा-दा-बिंग, आपने इसे पाया।

ध्यान दें कि प्रत्येक पुनरावर्ती कॉल केवल वर्तमान सबरेंज के साथ ही व्यवहार करती है, न कि (उदाहरण के लिए) वर्तमान स्थिति से ऊपर की सभी पंक्तियाँ। वर्तमान व्यवस्था में बस वे।

यहां आपके लिए कुछ छद्मकोड प्रस्तुत हैं:

bool numberSearch(int[][] arr, int value, int minX, int maxX, int minY, int maxY)

if (minX == maxX and minY == maxY and arr[minX,minY] != value)
    return false
if (arr[minX,minY] > value) return false;  // Early exits if the value can't be in 
if (arr[maxX,maxY] < value) return false;  // this subrange at all.
int nextX = (minX + maxX) / 2
int nextY = (minY + maxY) / 2
if (arr[nextX,nextY] == value)
{
    print nextX,nextY
    return true
}
else if (arr[nextX,nextY] < value)
{
    if (numberSearch(arr, value, minX, maxX, nextY + 1, maxY))
        return true
    return numberSearch(arr, value, nextX + 1, maxX, minY, nextY)
}
else
{
    if (numberSearch(arr, value, minX, nextX - 1, minY, maxY))
        return true
    reutrn numberSearch(arr, value, nextX, maxX, minY, nextY)
}

+1: यह एक O (लॉग (N)) रणनीति है, और इस प्रकार एक आदेश के रूप में अच्छा है क्योंकि एक प्राप्त करने जा रहा है।
रेक्स केर

3
@Rex Kerr - यह O (लॉग (N)) की तरह दिखता है, क्योंकि यह एक सामान्य बाइनरी खोज है, हालांकि, ध्यान दें कि प्रत्येक स्तर पर संभावित दो पुनरावर्ती कॉल हैं। इसका मतलब यह प्लेन लॉगरिदमिक की तुलना में बहुत खराब है। मुझे विश्वास नहीं है कि बदतर मामला ओ (एम + एन) की तुलना में बेहतर है, क्योंकि संभवतः, हर पंक्ति या हर कॉलम को खोजना होगा। मुझे लगता है कि यह एल्गोरिथ्म बहुत सारे मूल्यों के लिए सबसे खराब स्थिति को हरा सकता है, हालांकि। और सबसे अच्छी बात यह है कि यह पैरालिसेबल है, क्योंकि यही वह जगह है जहां हार्डवेयर हाल ही में है।
जेफरी एल व्हिटलेज

1
@ जेएलडब्ल्यू: यह ओ (लॉग (एन)) है - लेकिन यह वास्तव में ओ (लॉग_ (4/3) (एन ^ 2)) या ऐसा ही कुछ है। नीचे Svante का जवाब देखें। आपका जवाब वास्तव में एक ही है (यदि आप जिस तरह से मुझे लगता है कि आपने किया था में पुनरावर्ती का मतलब था)।
रेक्स केर

1
@ शांते - उपप्रकार ओवरलैप नहीं होते हैं। पहले विकल्प में, उनके पास सामान्य रूप से कोई वाई-तत्व नहीं है। दूसरे विकल्प में, उनके पास कोई सामान्य तत्व नहीं है।
जेफरी एल व्हिटलेज

1
मुझे यकीन नहीं है कि यह लघुगणक है। मैंने अनुमानित पुनरावृत्ति संबंध T (0) = 1, T (A) = T (A / 2) + T (A / 4) + 1 का उपयोग करके जटिलता की गणना की, जहाँ A खोज क्षेत्र है, और T के साथ समाप्त हुआ ( A) = O (Fib (lg (A))), जो लगभग O (A ^ 0.7) है और O (n + m) से भी बदतर है जो O (A ^ 0.5) है। हो सकता है कि मैंने कुछ बेवकूफी भरी गलती की हो, लेकिन ऐसा लगता है कि एल्गोरिथ्म व्यर्थ की शाखाओं के नीचे जाने में बहुत समय बर्बाद कर रहा है।
क्रेग गिडनी

6

अब तक दिए गए दो मुख्य उत्तर यकीनन O(log N)"ZigZag विधि" और O(N+M)द्विआधारी खोज विधि प्रतीत होते हैं । मैंने सोचा कि मैं कुछ तरीकों की तुलना कुछ अलग-अलग सेटअपों के साथ कर रहा हूँ। यहाँ विवरण हैं:

सरणी हर टेस्ट में एन x एन स्क्वायर है, जिसमें एन 125 से 8000 तक अलग है (मेरा सबसे बड़ा जेवीएम हीप संभाल सकता है)। प्रत्येक सरणी आकार के लिए, मैंने एकल डालने के लिए सरणी में एक यादृच्छिक स्थान चुना 2। मैंने तब 3हर जगह संभव (2 के दाईं ओर और नीचे) को रखा और फिर बाकी सरणी को भर दिया1। पहले के टिप्पणीकारों में से कुछ को लगता था कि इस प्रकार के सेटअप से दोनों एल्गोरिदम के लिए सबसे खराब स्थिति होगी। प्रत्येक सरणी आकार के लिए, मैंने 2 (खोज लक्ष्य) के लिए 100 अलग-अलग यादृच्छिक स्थान चुने और परीक्षण चलाया। मैंने औसत एल्गोरिथ्म के लिए एवीजी रन टाइम और सबसे खराब केस रन टाइम रिकॉर्ड किया। क्योंकि जावा में अच्छे एमएस रीडिंग प्राप्त करने के लिए यह बहुत तेज़ी से हो रहा था, और क्योंकि मुझे जावा के नैनो टाइम () पर भरोसा नहीं है, मैंने हर बार एक परीक्षण को एक समान पूर्वाग्रह कारक जोड़ने के लिए 1000 बार दोहराया। यहाँ परिणाम हैं:

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

ज़िगज़ैग ने एवीजी और सबसे खराब स्थिति दोनों के लिए हर परीक्षण में बाइनरी को हराया, हालांकि, वे सभी एक-दूसरे के परिमाण के क्रम में कम या ज्यादा होते हैं।

यहाँ जावा कोड है:

public class SearchSortedArray2D {

    static boolean findZigZag(int[][] a, int t) {
        int i = 0;
        int j = a.length - 1;
        while (i <= a.length - 1 && j >= 0) {
            if (a[i][j] == t) return true;
            else if (a[i][j] < t) i++;
            else j--;
        }
        return false;
    }

    static boolean findBinarySearch(int[][] a, int t) {
        return findBinarySearch(a, t, 0, 0, a.length - 1, a.length - 1);
    }

    static boolean findBinarySearch(int[][] a, int t,
            int r1, int c1, int r2, int c2) {
        if (r1 > r2 || c1 > c2) return false; 
        if (r1 == r2 && c1 == c2 && a[r1][c1] != t) return false;
        if (a[r1][c1] > t) return false;
        if (a[r2][c2] < t) return false;

        int rm = (r1 + r2) / 2;
        int cm = (c1 + c2) / 2;
        if (a[rm][cm] == t) return true;
        else if (a[rm][cm] > t) {
            boolean b1 = findBinarySearch(a, t, r1, c1, r2, cm - 1);
            boolean b2 = findBinarySearch(a, t, r1, cm, rm - 1, c2);
            return (b1 || b2);
        } else {
            boolean b1 = findBinarySearch(a, t, r1, cm + 1, rm, c2);
            boolean b2 = findBinarySearch(a, t, rm + 1, c1, r2, c2);
            return (b1 || b2);
        }
    }

    static void randomizeArray(int[][] a, int N) {
        int ri = (int) (Math.random() * N);
        int rj = (int) (Math.random() * N);
        a[ri][rj] = 2;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if (i == ri && j == rj) continue;
                else if (i > ri || j > rj) a[i][j] = 3;
                else a[i][j] = 1;
            }
        }
    }

    public static void main(String[] args) {

        int N = 8000;
        int[][] a = new int[N][N];
        int randoms = 100;
        int repeats = 1000;

        long start, end, duration;
        long zigMin = Integer.MAX_VALUE, zigMax = Integer.MIN_VALUE;
        long binMin = Integer.MAX_VALUE, binMax = Integer.MIN_VALUE;
        long zigSum = 0, zigAvg;
        long binSum = 0, binAvg;

        for (int k = 0; k < randoms; k++) {
            randomizeArray(a, N);

            start = System.currentTimeMillis();
            for (int i = 0; i < repeats; i++) findZigZag(a, 2);
            end = System.currentTimeMillis();
            duration = end - start;
            zigSum += duration;
            zigMin = Math.min(zigMin, duration);
            zigMax = Math.max(zigMax, duration);

            start = System.currentTimeMillis();
            for (int i = 0; i < repeats; i++) findBinarySearch(a, 2);
            end = System.currentTimeMillis();
            duration = end - start;
            binSum += duration;
            binMin = Math.min(binMin, duration);
            binMax = Math.max(binMax, duration);
        }
        zigAvg = zigSum / randoms;
        binAvg = binSum / randoms;

        System.out.println(findZigZag(a, 2) ?
                "Found via zigzag method. " : "ERROR. ");
        //System.out.println("min search time: " + zigMin + "ms");
        System.out.println("max search time: " + zigMax + "ms");
        System.out.println("avg search time: " + zigAvg + "ms");

        System.out.println();

        System.out.println(findBinarySearch(a, 2) ?
                "Found via binary search method. " : "ERROR. ");
        //System.out.println("min search time: " + binMin + "ms");
        System.out.println("max search time: " + binMax + "ms");
        System.out.println("avg search time: " + binAvg + "ms");
    }
}

1
+1 याय, डेटा। :) यह देखना भी दिलचस्प हो सकता है कि ये दोनों दृष्टिकोण एनएक्सएम सरणियों पर कैसे किराया करते हैं, क्योंकि द्विआधारी खोज ऐसा लगता है कि यह सहज रूप से अधिक उपयोगी हो जाना चाहिए जितना अधिक हम 1-आयामी मामले से संपर्क करते हैं।
नैट कोहल

5

यह समस्या पर निचली सीमा का एक छोटा सा सबूत है।

आप इसे रैखिक समय (सरणी आयामों के संदर्भ में, तत्वों की संख्या) से बेहतर नहीं कर सकते। नीचे दिए गए सरणी में, प्रत्येक के रूप में चिह्नित तत्व *5 या 6 या (स्वतंत्र रूप से अन्य) हो सकते हैं। इसलिए यदि आपका लक्ष्य मान 6 (या 5) है, तो एल्गोरिथ्म को उन सभी की जांच करने की आवश्यकता है।

1 2 3 4 *
2 3 4 * 7
3 4 * 7 8
4 * 7 8 9
* 7 8 9 10

बेशक यह बड़े सरणियों के रूप में अच्छी तरह से फैलता है। इसका मतलब है कि यह उत्तर इष्टतम है।

अपडेट: जैसा कि जेफरी एल व्हिटलेज ने बताया है, यह केवल इष्टतम है जैसा कि रनिंग टाइम बनाम इनपुट डेटा साइज (सिंगल वैरिएबल के रूप में माना जाता है) पर कम होता है। दोनों एरे आयामों पर दो-चर फ़ंक्शन के रूप में चल रहे समय में सुधार किया जा सकता है।


आपने यह प्रदर्शित नहीं किया है कि यह उत्तर इष्टतम है। उदाहरण के लिए, एक सरणी जो दस-पार है और एक-लाख नीचे है जिसमें पांचवीं पंक्ति में लक्ष्य मान से अधिक सभी मान शामिल हैं। उस स्थिति में प्रस्तावित एल्गोरिथ्म लक्ष्य के करीब पहुंचने से पहले 999,995 मूल्यों की खोज करेगा। मेरा जैसा द्विभाजित एल्गोरिथ्म लक्ष्य प्राप्त करने से पहले केवल 18 मानों की खोज करेगा। और यह (asymtotically) अन्य सभी मामलों में प्रस्तावित एल्गोरिथ्म से बदतर नहीं है।
जेफरी एल व्हाइटलेज

@ जेफ्री: यह निराशावादी मामले के लिए समस्या पर एक कम बाध्य है। आप अच्छे इनपुट के लिए ऑप्टिमाइज़ कर सकते हैं, लेकिन ऐसे इनपुट मौजूद हैं जहाँ आप रैखिक से बेहतर नहीं कर सकते।
राफेल डोवगार्ड

हां, ऐसे इनपुट मौजूद हैं जहां आप रैखिक से बेहतर नहीं कर सकते। जिस स्थिति में मेरा एल्गोरिथ्म उस रैखिक खोज को करता है। लेकिन ऐसे अन्य इनपुट हैं जहां आप रैखिक की तुलना में बेहतर तरीके से कर सकते हैं । इस प्रकार प्रस्तावित समाधान इष्टतम नहीं है, क्योंकि यह हमेशा एक रैखिक खोज करता है।
जेफरी एल व्हाइटलेज

इससे पता चलता है कि एल्गोरिथ्म को बिग ओमेगा (न्यूनतम (n, m)) समय लेना चाहिए, न कि BigOmega (n + m)। यही कारण है कि जब आप एक आयाम काफी छोटा होता है तो आप बहुत बेहतर कर सकते हैं। उदाहरण के लिए, यदि आप जानते हैं कि केवल 1 पंक्ति होगी, तो आप लॉगरिदमिक समय में समस्या को हल कर सकते हैं। मुझे लगता है कि एक इष्टतम एल्गोरिथ्म में O (मिनट (n + m, n lg m, m lg n)) लगेगा।
क्रेग गिदनी

तदनुसार जवाब अपडेट करें।
राफेल डोवगार्ड

4

मुझे लगता है कि यहाँ उत्तर है और यह किसी भी प्रकार के मैट्रिक्स के लिए काम करता है

bool findNum(int arr[][ARR_MAX],int xmin, int xmax, int ymin,int ymax,int key)
{
    if (xmin > xmax || ymin > ymax || xmax < xmin || ymax < ymin) return false;
    if ((xmin == xmax) && (ymin == ymax) && (arr[xmin][ymin] != key)) return false;
    if (arr[xmin][ymin] > key || arr[xmax][ymax] < key) return false;
    if (arr[xmin][ymin] == key || arr[xmax][ymax] == key) return true;

    int xnew = (xmin + xmax)/2;
    int ynew = (ymin + ymax)/2;

    if (arr[xnew][ynew] == key) return true;
    if (arr[xnew][ynew] < key)
    {
        if (findNum(arr,xnew+1,xmax,ymin,ymax,key))
            return true;
        return (findNum(arr,xmin,xmax,ynew+1,ymax,key));
    } else {
        if (findNum(arr,xmin,xnew-1,ymin,ymax,key))
            return true;
        return (findNum(arr,xmin,xmax,ymin,ynew-1,key));
    }
}

1

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

अगर मैं आपके उदाहरण में 3 की तलाश कर रहा हूं, तो मैंने पहली पंक्ति में 4 तक पढ़ा, जब तक कि मैं 4 हिट नहीं कर देता, तब 3 से अधिक छोटी संख्या (विकर्ण सहित) देखें:

1 2 4 5 6
2 3 5 7 8
4 6 8 10 10
5 8 9 10 11

अब मैं 3 से कम संख्या वालों के लिए भी यही करता हूं:

1 2 4 5 6
2 3 5 7 8
4 6 8 10 10
5 8 9 10 11

अब मैं पूछता हूं, क्या दो सीमाओं के अंदर कुछ है? यदि हां, तो यह होना चाहिए 3. यदि नहीं, तो कोई नहीं है 3. अप्रत्यक्ष की तरह जब से मुझे वास्तव में नंबर नहीं मिला, मैं सिर्फ यह कहता हूं कि यह होना चाहिए। इसमें सभी 3 की गिनती का अतिरिक्त बोनस है।

मैंने कुछ उदाहरणों पर यह कोशिश की और यह ठीक काम करने लगता है।


कोई टिप्पणी के साथ एक नीचे वोट? मुझे लगता है कि यह ओ (एन ^ 1/2) है क्योंकि सबसे खराब स्थिति के प्रदर्शन के लिए विकर्ण की जांच की आवश्यकता होती है। कम से कम मुझे एक काउंटर उदाहरण दिखाएं जहां यह विधि काम नहीं करती है!
गार्मबो

+1: अच्छा समाधान ... रचनात्मक, और अच्छा है कि यह सभी समाधान पाता है।
टोनी डेलरो

1

सरणी के विकर्ण के माध्यम से द्विआधारी खोज सबसे अच्छा विकल्प है। हम पता लगा सकते हैं कि क्या तत्व विकर्ण में तत्वों से कम या बराबर है।


0

A. उन लाइनों पर एक द्विआधारी खोज करें जहां लक्ष्य संख्या हो सकती है।

B. इसे एक ग्राफ बनाएं: हमेशा सबसे छोटी परिकल्पित पड़ोसी नोड को लेते हुए नंबर की तलाश करें और बहुत बड़ी संख्या पाए जाने पर पीछे हट जाएं।


0

द्विआधारी खोज सबसे अच्छा तरीका होगा, इमो। 1/2 x से शुरू, 1/2 y इसे आधे में काट देगा। IE एक 5x5 वर्ग x == 2 / y == 3 जैसा कुछ होगा। मैंने लक्षित मूल्य की दिशा में एक मान नीचे और एक मान बेहतर क्षेत्र तक गोल किया।

स्पष्टता के लिए अगला पुनरावृत्ति आपको x == 1 / y == 2 OR x == 3 / y == 5 जैसा कुछ देगा।


0

ठीक है, शुरू करने के लिए, मान लें कि हम एक वर्ग का उपयोग कर रहे हैं।

1 2 3
2 3 4
3 4 5

1. एक वर्ग की खोज

मैं विकर्ण पर एक द्विआधारी खोज का उपयोग करेगा। लक्ष्य छोटी संख्या का पता लगाना है जो लक्ष्य संख्या से कड़ाई से कम नहीं है।

मैं देख रहा हूँ कहो 4उदाहरण के लिए, तो मैं पता लगाने खत्म होगा 5पर (2,2)

फिर, मैं आश्वस्त हूँ कि यदि 4तालिका में है, यह एक स्थिति में या तो है (x,2)या (2,x)साथ xमें [0,2]। खैर, यह सिर्फ 2 द्विआधारी खोज है।

जटिलता कठिन नहीं है: O(log(N))(लंबाई की सीमाओं पर 3 बाइनरी खोज N)

2. एक आयत, भोली दृष्टिकोण की खोज

बेशक, यह तब Nऔर अधिक जटिल हो जाता है जब और Mअलग (एक आयत के साथ), इस पतित मामले पर विचार करें:

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

और मान लें कि मैं खोज रहा हूं 9... विकर्ण दृष्टिकोण अभी भी अच्छा है, लेकिन विकर्ण की परिभाषा बदल जाती है। यहाँ मेरा विकर्ण है [1, (5 or 6), 17]। मान लीजिए कि मैंने उठाया [1,5,17], तो मुझे पता है कि यदि 9तालिका में है तो यह सबपार्टर में है:

            5  6  7  8
            6  7  8  9
10 11 12 13 14 15 16

इससे हमें 2 आयतें मिलती हैं:

5 6 7 8    10 11 12 13 14 15 16
6 7 8 9

तो हम फिर से पा सकते हैं! शायद कम तत्वों वाले व्यक्ति द्वारा शुरुआत (हालांकि इस मामले में यह हमें मारता है)।

मुझे यह कहना चाहिए कि यदि किसी एक आयाम से कम है 3, तो हम विकर्ण तरीकों को लागू नहीं कर सकते हैं और एक द्विआधारी खोज का उपयोग करना चाहिए। यहाँ इसका मतलब होगा:

  • बाइनरी खोज को लागू करें 10 11 12 13 14 15 16, नहीं मिला
  • बाइनरी खोज को लागू करें 5 6 7 8, नहीं मिला
  • बाइनरी खोज को लागू करें 6 7 8 9, नहीं मिला

यह मुश्किल है क्योंकि अच्छा प्रदर्शन पाने के लिए आप सामान्य आकार के आधार पर कई मामलों में अंतर कर सकते हैं ...।

3. एक आयत, क्रूर दृष्टिकोण की खोज करना

यदि हम एक वर्ग से निपटते हैं तो यह बहुत आसान होगा ... तो चलो बस वर्ग चीजों को ऊपर उठाएं।

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

अब हमारे पास एक वर्ग है।

बेशक, हम वास्तव में उन पंक्तियों को नहीं बनाएंगे, हम केवल उनका अनुकरण कर सकते हैं।

def get(x,y):
  if x < N and y < M: return table[x][y]
  else: return table[N-1][M-1]            # the max

इसलिए यह अधिक मेमोरी (गति की लागत पर, शायद कैश पर निर्भर करता है ... ओह अच्छी तरह से: पी पर कब्जा किए बिना एक वर्ग की तरह व्यवहार करता है)


0

संपादित करें:

मैंने प्रश्न को गलत समझा। जैसा कि टिप्पणियां इंगित करती हैं यह केवल अधिक प्रतिबंधित मामले में काम करता है।

C जैसी भाषा में जो डेटा को पंक्ति-प्रमुख क्रम में संग्रहीत करता है, बस इसे 1D सरणी आकार n * m के रूप में मानते हैं और एक द्विआधारी खोज का उपयोग करते हैं।


हां, इसे जितना अधिक होना चाहिए उससे अधिक जटिल क्यों है।
इरिक्कलेन

ऐरे को क्रमबद्ध नहीं किया गया है, इस प्रकार कोई बिन खोज उस पर लागू नहीं की जा सकती है
माइलिनियर

1
यह तभी काम करेगा जब प्रत्येक पंक्ति का अंतिम तत्व अगली पंक्ति के पहले तत्व से अधिक हो, जो समस्या का प्रस्ताव करने की तुलना में बहुत अधिक प्रतिबंधात्मक आवश्यकता है।
जेफरी एल व्हाइटलेज

धन्यवाद, मैंने अपना उत्तर संपादित कर लिया है। ध्यान से पर्याप्त रूप से नहीं पढ़ा, विशेष रूप से उदाहरण सरणी।
ह्यूग ब्रैकेट

0

मेरे पास एक पुनरावर्ती विभाजन और विजय समाधान है। एक कदम के लिए मूल विचार यह है: हम जानते हैं कि वाम-ऊपरी (LU) सबसे छोटा है और दायां-निचला (RB) सबसे बड़ा नंबर है, इसलिए दिए गए No (N) को चाहिए: N> = LU और N <=। आरबी

IF N == LU और N == RB :::: एलीमेंट फाउंड एंड एबॉर्ट पोज़िशन / इंडेक्स लौटाता है यदि N> = LU और N <= RB = FALSE, नहीं है और गर्भपात नहीं होता है। यदि N> = LU और N <= RB = TRUE, 2 डी सरणी को 2 डी सरणी के 4 बराबर भागों में तार्किक रूप से विभाजित करें .. और फिर सभी चार उप-सरणी में एक ही एल्गो चरण लागू करें।

मेरा अल्गो सही है मैंने अपने दोस्तों पीसी पर लागू किया है। जटिलता: प्रत्येक 4 तुलनाओं को इसके सबसे खराब मामले में तत्वों की कुल संख्या को एक-चौथाई तक घटाने के लिए इस्तेमाल किया जा सकता है .. इसलिए मेरी जटिलता 1 + 4 x lg (n) + 4 की आती है, लेकिन वास्तव में O पर काम करने की उम्मीद है (एन)

मुझे लगता है कि जटिलता की मेरी गणना में कहीं न कहीं कुछ गलत है, कृपया सही करें यदि ऐसा है ..


0

इष्टतम समाधान शीर्ष-बाएं कोने पर शुरू करना है, जिसमें न्यूनतम मूल्य है। किसी तत्व को हिट करने तक तिरछे नीचे दाईं ओर ले जाएं, जिसका मूल्य> दिए गए तत्व का मूल्य = है। यदि तत्व का मान दिए गए तत्व के बराबर है, तो पाया गया रिटर्न सही है।

अन्यथा, यहां से हम दो तरीकों से आगे बढ़ सकते हैं।

रणनीति 1:

  1. कॉलम में ऊपर जाएँ और दिए गए तत्व को तब तक खोजें जब तक हम अंत तक नहीं पहुँच जाते। अगर मिला, तो जैसा मिला, वैसा ही लौटा
  2. पंक्ति में बाईं ओर ले जाएँ और दिए गए तत्व को तब तक खोजें जब तक हम अंत तक नहीं पहुँच जाते। अगर मिला, तो जैसा मिला, वैसा ही लौटा
  3. वापसी झूठी के रूप में मिली

रणनीति 2: आइए हम पंक्ति सूचकांक को निरूपित करते हैं और जिस तिरछे तत्व को हमने रोका है, उसके स्तंभ सूचकांक को निरूपित करते हैं। (यहां, हमारे पास i = j, BTW है)। आज्ञा देना k = १।

  • Ik = = 0 तक नीचे दिए चरणों को दोहराएं
    1. अगर एक [ik] [j] दिए गए तत्व के बराबर है तो खोजें। यदि हां, तो सही पाया गया रिटर्न।
    2. अगर एक [i] [jk] दिए गए तत्व के बराबर है तो खोजें। यदि हां, तो सही पाया गया रिटर्न।
    3. वृद्धि k

1 2 4 5 6
2 3 5 7 8
4 6 8 9 10
5 8 9 10 11


0
public boolean searchSortedMatrix(int arr[][] , int key , int minX , int maxX , int minY , int maxY){

    // base case for recursion
    if(minX > maxX || minY > maxY)
        return false ;
    // early fails
    // array not properly intialized
    if(arr==null || arr.length==0)
        return false ;
    // arr[0][0]> key return false
    if(arr[minX][minY]>key)
        return false ;
    // arr[maxX][maxY]<key return false
    if(arr[maxX][maxY]<key)
        return false ;
    //int temp1 = minX ;
    //int temp2 = minY ;
    int midX = (minX+maxX)/2 ;
    //if(temp1==midX){midX+=1 ;}
    int midY = (minY+maxY)/2 ;
    //if(temp2==midY){midY+=1 ;}


    // arr[midX][midY] = key ? then value found
    if(arr[midX][midY] == key)
        return true ;
    // alas ! i have to keep looking

    // arr[midX][midY] < key ? search right quad and bottom matrix ;
    if(arr[midX][midY] < key){
        if( searchSortedMatrix(arr ,key , minX,maxX , midY+1 , maxY))
            return true ;
        // search bottom half of matrix
        if( searchSortedMatrix(arr ,key , midX+1,maxX , minY , maxY))
            return true ;
    }
    // arr[midX][midY] > key ? search left quad matrix ;
    else {
         return(searchSortedMatrix(arr , key , minX,midX-1,minY,midY-1));
    }
    return false ;

}

0

मेरा सुझाव है, सभी वर्णों को एक में संग्रहीत करें 2D list । यदि आवश्यक हो तो सूची में मौजूद तत्व का सूचकांक खोजें।

यदि प्रिंट संदेश उचित रूप में मौजूद नहीं है, तो प्रिंट पंक्ति और कॉलम को निम्नानुसार लिखें:

row = (index/total_columns) तथा column = (index%total_columns -1)

यह केवल एक सूची में द्विआधारी खोज समय को उकसाएगा।

कृपया कोई सुधार सुझाएं। :)


0

यदि O (M log (N)) समाधान MxN सरणी के लिए ठीक है -

template <size_t n>
struct MN * get(int a[][n], int k, int M, int N){
  struct MN *result = new MN;
  result->m = -1;
  result->n = -1;

  /* Do a binary search on each row since rows (and columns too) are sorted. */
  for(int i = 0; i < M; i++){
    int lo = 0; int hi = N - 1;
    while(lo <= hi){
      int mid = lo + (hi-lo)/2;
      if(k < a[i][mid]) hi = mid - 1;
      else if (k > a[i][mid]) lo = mid + 1;
      else{
        result->m = i;
        result->n = mid;
        return result;
      }
    }
  }
  return result;
}

कार्य C ++ डेमो।

कृपया मुझे बताएं कि क्या यह काम नहीं करेगा या यदि कोई बग है तो इसे बताएं।


0

मैं एक दशक के बेहतर हिस्से के लिए साक्षात्कार में यह सवाल पूछ रहा हूं और मुझे लगता है कि केवल एक ही व्यक्ति है जो एक इष्टतम एल्गोरिदम के साथ आने में सक्षम है।

मेरा समाधान हमेशा रहा है:

  1. बाइनरी मध्य विकर्ण की खोज करते हैं, जो कि आइटम पर युक्त, नीचे और दाएं चलने वाला विकर्ण है (rows.count/2, columns.count/2)

  2. यदि लक्ष्य संख्या मिली है, तो सही लौटें।

  3. अन्यथा, दो नंबर ( uऔर v) ऐसे पाए जाएंगे जो uलक्ष्य से छोटा है, लक्ष्य vसे बड़ा है, और vएक सही और एक नीचे से है u

  4. फिर से uऔर ऊपर vऔर नीचे uऔर बाईं ओर एक के दाईं ओर उप-मैट्रिक्स की खोज करें v

मेरा मानना ​​है कि यह नैट द्वारा यहां दिए गए एल्गोरिदम पर एक सख्त सुधार है , क्योंकि विकर्ण की खोज अक्सर आधे से अधिक खोज स्थान (यदि मैट्रिक्स वर्ग के करीब है) की कमी की अनुमति देता है, जबकि एक पंक्ति या स्तंभ की खोज हमेशा एक उन्मूलन के रूप में होती है बिल्कुल आधा।

यहाँ कोड है (शायद बहुत तेज़ी से नहीं) स्विफ्ट:

import Cocoa

class Solution {
    func searchMatrix(_ matrix: [[Int]], _ target: Int) -> Bool {
        if (matrix.isEmpty || matrix[0].isEmpty) {
            return false
        }

        return _searchMatrix(matrix, 0..<matrix.count, 0..<matrix[0].count, target)
    }

    func _searchMatrix(_ matrix: [[Int]], _ rows: Range<Int>, _ columns: Range<Int>, _ target: Int) -> Bool {
        if (rows.count == 0 || columns.count == 0) {
            return false
        }
        if (rows.count == 1) {
            return _binarySearch(matrix, rows.lowerBound, columns, target, true)
        }
        if (columns.count == 1) {
            return _binarySearch(matrix, columns.lowerBound, rows, target, false)
        }

        var lowerInflection = (-1, -1)
        var upperInflection = (Int.max, Int.max)
        var currentRows = rows
        var currentColumns = columns
        while (currentRows.count > 0 && currentColumns.count > 0 && upperInflection.0 > lowerInflection.0+1) {
            let rowMidpoint = (currentRows.upperBound + currentRows.lowerBound) / 2
            let columnMidpoint = (currentColumns.upperBound + currentColumns.lowerBound) / 2
            let value = matrix[rowMidpoint][columnMidpoint]
            if (value == target) {
                return true
            }

            if (value > target) {
                upperInflection = (rowMidpoint, columnMidpoint)
                currentRows = currentRows.lowerBound..<rowMidpoint
                currentColumns = currentColumns.lowerBound..<columnMidpoint
            } else {
                lowerInflection = (rowMidpoint, columnMidpoint)
                currentRows = rowMidpoint+1..<currentRows.upperBound
                currentColumns = columnMidpoint+1..<currentColumns.upperBound
            }
        }
        if (lowerInflection.0 == -1) {
            lowerInflection = (upperInflection.0-1, upperInflection.1-1)
        } else if (upperInflection.0 == Int.max) {
            upperInflection = (lowerInflection.0+1, lowerInflection.1+1)
        }

        return _searchMatrix(matrix, rows.lowerBound..<lowerInflection.0+1, upperInflection.1..<columns.upperBound, target) || _searchMatrix(matrix, upperInflection.0..<rows.upperBound, columns.lowerBound..<lowerInflection.1+1, target)
    }

    func _binarySearch(_ matrix: [[Int]], _ rowOrColumn: Int, _ range: Range<Int>, _ target: Int, _ searchRow : Bool) -> Bool {
        if (range.isEmpty) {
            return false
        }

        let midpoint = (range.upperBound + range.lowerBound) / 2
        let value = (searchRow ? matrix[rowOrColumn][midpoint] : matrix[midpoint][rowOrColumn])
        if (value == target) {
            return true
        }

        if (value > target) {
            return _binarySearch(matrix, rowOrColumn, range.lowerBound..<midpoint, target, searchRow)
        } else {
            return _binarySearch(matrix, rowOrColumn, midpoint+1..<range.upperBound, target, searchRow)
        }
    }
}

-1

एक वर्ग मैट्रिक्स को निम्नानुसार दिया गया है:

[एबीसी]
[def]
[ijk]

हम जानते हैं कि एक <c, d <f, i <k। क्या हम नहीं जानते कि क्या d <c या d> c आदि है। हमारे पास केवल 1-आयाम में गारंटी है।

अंतिम तत्वों (c, f, k) को देखते हुए, हम एक प्रकार का फ़िल्टर कर सकते हैं: N <c? खोज (): अगला () इस प्रकार, हमारे पास पंक्तियों पर एन पुनरावृत्तियां हैं, प्रत्येक पंक्ति के साथ या तो हे (लॉग (एन)) बाइनरी खोज के लिए या ओ (1) यदि फ़िल्टर किया गया है।

मुझे एक उदाहरण दिया जहाँ N = j,

1) जाँच पंक्ति 1. j <c? (नहीं, आगे जाओ)

2) चेक पंक्ति 2. जे <एफ? (हां, बिन खोज कुछ नहीं मिलता)

3) जाँच पंक्ति 3. j <k? (हाँ, बिन खोज यह पाता है)

N = q के साथ फिर से प्रयास करें,

1) जाँच पंक्ति 1. q <c? (नहीं, आगे जाओ)

2) जाँच पंक्ति 2. क्यू <एफ? (नहीं, आगे जाओ)

3) जाँच पंक्ति 3. q <k? (नहीं, आगे जाओ)

वहाँ एक बेहतर समाधान शायद वहाँ है, लेकिन यह समझाने के लिए आसान है .. :)


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.