किसी तत्व को खोजने का कुशल तरीका


88

हाल ही में मेरा एक साक्षात्कार था, जहां उन्होंने मुझसे " खोज " की " प्रश्न पूछा था।
सवाल यह था:

मान लें कि (सकारात्मक) पूर्णांकों की एक सरणी है, जिनमें से प्रत्येक तत्व +1या तो है-1 अपने आसन्न तत्वों की तुलना में ।

उदाहरण:

array = [4,5,6,5,4,3,2,3,4,5,6,7,8];

अब खोजते हैं 7 और अपनी स्थिति वापस करें।

मैंने इसका उत्तर दिया:

मूल्यों को एक अस्थायी सरणी में संग्रहीत करें, उन्हें सॉर्ट करें, और फिर बाइनरी खोज लागू करें।

यदि तत्व पाया जाता है, तो अस्थायी सरणी में अपनी स्थिति लौटाएं।
(यदि संख्या दो बार हो रही है तो इसकी पहली घटना लौटाएं)

लेकिन, वे इस जवाब से संतुष्ट नहीं दिखे।

सही उत्तर क्या है?


4
जहाँ तक मुझे पता है, एक रेखीय खोज एक तत्व के सूचकांक को खोजने के लिए एक अच्छा तरीका है। मुझे यकीन नहीं है कि एक और खोज एल्गोरिथ्म अभी तक एक तत्व के सूचकांक का पता लगाने में कुशल है।
सीन फ्रांसिस एन। बैलैस

4
यदि 7 की गारंटी है तो केवल एक बार दिखाई दें या यदि यह मायने नहीं रखता है कि कौन सा 7 लौटा है तो आप कोलमैन के उत्तर के रैखिक एल्गोरिथ्म में कुछ और सुधार कर सकते हैं।
user1942027

52
यदि आपके मूल समाधान को छंटाई की आवश्यकता है, तो यह भोले रैखिक खोज से भी बदतर है। आपको लगता है कि इसके बारे में पता नहीं है।
क्यूबप्लस 42

5
सॉर्टिंग के लिए O (nlogn) की आवश्यकता होती है, और एक बाइनरी सर्च O (logn) होता है। यदि आपको बड़े सरणी से कई मानों की खोज करने की आवश्यकता है, तो आपका उत्तर बेहतर हो सकता है, लेकिन यदि आप केवल एक बार खोजना चाहते हैं, तो O (n) एल्गोरिदम बेहतर हो सकता है।
jingyu9575

23
मैं नहीं जानता कि किसी और ने इसका उल्लेख क्यों किया है: आपका तरीका न केवल अक्षम था, यह गलत था , और यह केवल अक्षमता से बहुत खराब है। आवश्यकता मूल सरणी में दिए गए नंबर की स्थिति के लिए है । आपकी विधि क्रमबद्ध सरणी में संख्या की स्थिति लौटाती है । अब, आप साधारण स्थिति को पुन: क्रमबद्ध करने के लिए सरल सरणी को ट्यूपल्स (संख्या, orig_pos) की एक सरणी में परिवर्तित करके प्राप्त कर सकते हैं । लेकिन आपने इसका उल्लेख नहीं किया है, इसलिए मैं अनुमान लगा रहा हूं कि आपने साक्षात्कार में इसका उल्लेख नहीं किया है।
टॉम ज़िच

जवाबों:


125

आप उन चरणों के साथ एक रेखीय खोज कर सकते हैं जो अक्सर 1 से अधिक होते हैं। महत्वपूर्ण अवलोकन यह है कि अगर उदाहरण के लिए array[i] == 4और 7 अभी तक प्रकट नहीं हुए हैं, तो 7 के लिए अगला उम्मीदवार सूचकांक में है i+3। थोड़ी देर के लूप का उपयोग करें जो बार-बार सीधे अगले व्यवहार्य उम्मीदवार के पास जाता है।

यहाँ एक कार्यान्वयन है, थोड़ा सामान्यीकृत है। यह kसरणी में पहली घटना को पाता है (+ = 1 प्रतिबंध के अधीन) या -1यदि ऐसा नहीं होता है:

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

int first_occurence(int k, int array[], int n);

int main(void){
    int a[] = {4,3,2,3,2,3,4,5,4,5,6,7,8,7,8};
    printf("7 first occurs at index %d\n",first_occurence(7,a,15));
    printf("but 9 first \"occurs\" at index %d\n",first_occurence(9,a,15));
    return 0;
}

int first_occurence(int k, int array[], int n){
    int i = 0;
    while(i < n){
        if(array[i] == k) return i;
        i += abs(k-array[i]);
    }
    return -1;
}

उत्पादन:

7 first occurs at index 11
but 9 first "occurs" at index -1

8
ठीक है कि मैं क्या सोच रहा था। यह है O(N), लेकिन मुझे नहीं लगता कि ऐसा करने का कोई तेज़ तरीका है।
आकारिरो यायाकोव

2
आप इसे अधिक तेज़ी से औसतन अधिक उम्मीदवारों के साथ कर सकते हैं (जैसे पहले और अंतिम), और फिर उस लक्ष्य के सबसे करीब से जा रहे हैं - अगर आपको केवल एक ही घटना खोजने की आवश्यकता है, तो पहले वाले की नहीं।
mkadunc

2
@mkadunc यह एक अच्छा विचार है। एक और अवलोकन यह है कि यदि पहला और अंतिम तत्व 7 तक फैला हुआ है तो उस विशेष स्थिति में आप एक द्विआधारी खोज का उपयोग कर सकते हैं (यदि आपको परवाह नहीं है कि आपको कौन सी 7 मिलती है)
जॉन कोलमैन

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

3
@ शापिरोयाकोव: जाँच से संयुक्त यदि किसी खंड के दोनों पक्षों के मानों के निचले से उच्चतर तक अंतराल k (7) शामिल है, तो यह अपने आप में एक उत्तर का हकदार है।
ग्रेबियर

35

आपका दृष्टिकोण बहुत जटिल है। आपको हर ऐरे तत्व की जांच करने की आवश्यकता नहीं है। पहले मान है 4तो, 7है कम से कम 7-4 तत्वों दूर, और आप उन छोड़ सकते हैं।

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

int main (void)
{
    int array[] = {4,5,6,5,4,3,2,3,4,5,6,7,8};
    int len = sizeof array / sizeof array[0];
    int i = 0;
    int steps = 0;
    while (i < len && array[i] != 7) {
        i += abs(7 - array[i]);
        steps++;
    }

    printf("Steps %d, index %d\n", steps, i);
    return 0;
}

कार्यक्रम का उत्पादन:

Steps 4, index 11

संपादित करें: @Raphael Miedl और @Martin Zabel की टिप्पणियों के बाद सुधार हुआ।


2
एक if ((skip = 7 - array[i]) < 1) skip = 1;निपिक, इसे अधिक जटिल लगता है और मेरी राय में इसे कम करता है। यदि array[i] == 200आप प्राप्त करते हैं -193और सिर्फ 1 बार हर बार छोड़ देते हैं तो भी आप सभी 193 को छोड़ सकते हैं। सिर्फ क्यों नहीं i += abs(7 - array[i])?
user1942027

1
आपको skip7 और के बीच पूर्ण अंतर पर सेट करना चाहिए array[i]
मार्टिन ज़ेबेल

@Rapeel Miedl नहीं, एक तत्व नहीं होगा 200, आप पास हो गए होंगे 7
वेन

3
@WeatherVane हमारे पास वह गारंटी नहीं है, केवल यह कि आसन्न मूल्य एक दूसरे से हैं +1/ हैं -1। तो यह सिर्फ हो सकता है array[0] == 200और दूसरों को ज्यादातर कर रहे हैं -1
15:19 पर user1942027

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

20

पारंपरिक रेखीय खोज की भिन्नता जाने का एक अच्छा तरीका हो सकता है। हमें एक तत्व कहना है array[i] = 2। अब, array[i + 1]या तो 1 या 3 (विषम) array[i + 2]होगा , (धनात्मक पूर्णांक केवल) 2 या 4 (सम संख्या) होगा।

इस तरह से जारी रखने पर, एक पैटर्न अवलोकनीय है - array[i + 2*n]यहां तक ​​कि संख्या भी होगी और इसलिए इन सभी सूचकांकों को अनदेखा किया जा सकता है।

इसके अलावा, हम यह देख सकते हैं

array[i + 3] = 1 or 3 or 5
array[i + 5] = 1 or 3 or 5 or 7

इसलिए, इंडेक्स i + 5को अगले चेक किया जाना चाहिए और इंडेक्स में पाए गए मूल्य के आधार पर, अगले इंडेक्स को जांचने के लिए एक लूप का उपयोग किया जा सकता है i + 5

हालांकि, इसमें जटिलता O(n)(एसिम्प्टोटिक जटिलता के संदर्भ में रैखिक समय) है, यह व्यावहारिक रूप से एक सामान्य रैखिक खोज से बेहतर है क्योंकि सभी सूचकांक का दौरा नहीं किया जाता है।

जाहिर है, यह सब उलटा होगा अगर array[i](हमारा शुरुआती बिंदु) विषम था।


8

जॉन कोलमैन द्वारा प्रस्तुत दृष्टिकोण वह है जो साक्षात्कारकर्ता उम्मीद कर रहा था, सभी संभावना में।
आप बहुत-सी जटिल जाने के इच्छुक हैं, तो आप उम्मीद छोड़ लंबाई में वृद्धि कर सकते हैं:
कॉल लक्ष्य मान कश्मीर । पहले तत्व के मूल्य v से स्थिति p पर शुरू करें और अंतर kv DV को निरपेक्ष मान av के साथ कहें । नकारात्मक खोजों को गति देने के लिए, अंतिम तत्व पर स्थिति o पर अन्य मान u के रूप में एक तिरछी नज़र रखें: यदि DV × du ऋणात्मक है, तो k मौजूद है (यदि k की कोई भी घटना स्वीकार्य है, तो आप यहां अनुक्रमणिका सीमा को संकीर्ण कर सकते हैं, जिस तरह से बाइनरी खोज करता है)। यदि av + au सरणी की लंबाई से अधिक है, तो k अनुपस्थित है। (यदि DV × du शून्य है, v या u बराबर k है।)
सूचकांक की वैधता को छोड़ते हुए: जांच करें ("अगला") स्थिति जहां अनुक्रम बीच में k के साथ v पर वापस आ सकता है o = p + 2*av:।
यदि DV × डु ऋणात्मक है, तो p + av से o-au तक k (पुनरावर्ती) खोजें;
यदि यह शून्य है, तो यू ओ के बराबर है।
यदि डु DV के बराबर है और बीच में मान k नहीं है, या au av से अधिक है,
या आप p + av से o-au तक k को खोजने में असफल हैं,
तो p=o; dv=du; av=au;रहने दें और जांच करते रहें।
(60 के दशक के ग्रंथों के लिए एक पूर्ण फ्लैश-बैक के लिए, कूरियर के साथ देखें। मेरा "1 दूसरा विचार" का उपयोग करना थाo = p + 2*av - 1, जो डु के बराबर है DV


4

चरण 1

पहले तत्व से शुरू करें और जांचें कि क्या यह 7. चलो कहते cहैं कि वर्तमान स्थिति का सूचकांक है। तो, शुरू में, c = 0

चरण 2

यदि यह 7 है, तो आपने सूचकांक पाया। यह है c। यदि आप सरणी के अंत तक पहुँच चुके हैं, तो विराम लें।

चरण 3

यदि यह नहीं है, तो 7 को कम से कम |array[c]-7|स्थिति में होना चाहिए क्योंकि आप केवल प्रति यूनिट एक इकाई जोड़ सकते हैं। इसलिए, |array[c]-7|अपने वर्तमान सूचकांक में जोड़ें , ग, और जांच के लिए फिर से STEP 2 पर जाएं।

सबसे खराब स्थिति में, जब वैकल्पिक 1 और 1s होते हैं, तो समय जटिलता O (n) तक पहुंच सकती है, लेकिन औसत मामलों को शीघ्रता से वितरित किया जाएगा।


यह जॉन कोलमैन के जवाब से कैसे अलग है? (यह सुझाव देने के अलावा कि |c-7|कहां |array[c]-7|बुलाया जाता है।)
ग्रेबर्ड

मैंने सिर्फ उसका जवाब देखा। मैं मानता हूं कि मूल विचार समान है।
अकेश्वर झा

मूल प्रश्न यह निर्धारित नहीं करता है कि सरणी 7. से छोटी संख्या से शुरू होती है। इसलिए array[c]-7सकारात्मक या नकारात्मक हो सकती है। abs()स्किप को आगे बढ़ाने से पहले आपको इसे लागू करना होगा।
arielf 30:15

हाँ तुम सही हो। कारण है कि मैं उपयोग कर रहा हूँ कि array[c] - 7मापांक ऑपरेटर के साथ, |array[c] - 7|
अखेश्वर झा

4

यहाँ मैं जावा में कार्यान्वयन दे रहा हूँ ...

public static void main(String[] args) 
{       
    int arr[]={4,5,6,5,4,3,2,3,4,5,6,7,8};
    int pos=searchArray(arr,7);

    if(pos==-1)
        System.out.println("not found");
    else
        System.out.println("position="+pos);            
}

public static int searchArray(int[] array,int value)
{
    int i=0;
    int strtValue=0;
    int pos=-1;

    while(i<array.length)
    {
        strtValue=array[i];

        if(strtValue<value)
        {
            i+=value-strtValue;
        }
        else if (strtValue==value)
        {
            pos=i;
            break;
        }
        else
        {
            i=i+(strtValue-value);
        }       
    }

    return pos;
}

2
कम से कम अर्ध-आधिकारिक सम्मेलन के साथ एक भाषा में अविभाजित कोड । यह जॉन कोलमैन और अखेश्वर के उत्तर से अलग कैसे है, "सी" उदारतापूर्वक टैग की व्याख्या करने के अलावा?
ग्रेबर्ड

3

यहाँ एक विभाजित और जीतना शैली समाधान है। (अधिक) बहीखाता पद्धति की कीमत पर, हम अधिक तत्वों को छोड़ सकते हैं; बाएं से दाएं स्कैन करने के बजाय, बीच में परीक्षण करें और दोनों दिशाओं में छोड़ें ।

#include <stdio.h>                                                               
#include <math.h>                                                                

int could_contain(int k, int left, int right, int width);                        
int find(int k, int array[], int lower, int upper);   

int main(void){                                                                  
    int a[] = {4,3,2,3,2,3,4,5,4,5,6,7,8,7,8};                                   
    printf("7 first occurs at index %d\n",find(7,a,0,14));                       
    printf("but 9 first \"occurs\" at index %d\n",find(9,a,0,14));               
    return 0;                                                                    
}                                                                                

int could_contain(int k, int left, int right, int width){                        
  return (width >= 0) &&                                                         
         (left <= k && k <= right) ||                                            
         (right <= k && k <= left) ||                                            
         (abs(k - left) + abs(k - right) < width);                               
}                                                                                

int find(int k, int array[], int lower, int upper){                              
  //printf("%d\t%d\n", lower, upper);                                            

  if( !could_contain(k, array[lower], array[upper], upper - lower )) return -1;  

  int mid = (upper + lower) / 2;                                                 

  if(array[mid] == k) return mid;                                                

  lower = find(k, array, lower + abs(k - array[lower]), mid - abs(k - array[mid]));
  if(lower >= 0 ) return lower;                                                    

  upper = find(k, array, mid + abs(k - array[mid]), upper - abs(k - array[upper]));
  if(upper >= 0 ) return upper;                                                  

  return -1;                                                                     

}

neal-fultz आपका उत्तर पहली घटना नहीं लौटाएगा, लेकिन खोज तत्व की कोई भी यादृच्छिक घटना, जैसा कि आप मध्य से शुरू कर रहे हैं और दोनों ओर से लंघन कर रहे हैं।
राम पतरा

पुनरावृत्ति के क्रम को बदलना पाठक के लिए एक अभ्यास के रूप में छोड़ दिया जाता है।
नील फुल्ट्ज

1
neal-fultz तब कृपया अपने प्रिंटफ़ () विधि कॉल में संदेश को संपादित करें।
राम पात्रा

2

const findMeAnElementsFunkyArray = (arr, ele, i) => {
  const elementAtCurrentIndex = arr[i];

  const differenceBetweenEleAndEleAtIndex = Math.abs(
    ele - elementAtCurrentIndex
  );

  const hop = i + differenceBetweenEleAndEleAtIndex;

  if (i >= arr.length) {
    return;
  }
  if (arr[i] === ele) {
    return i;
  }

  const result = findMeAnElementsFunkyArray(arr, ele, hop);

  return result;
};

const array = [4,5,6,5,4,3,2,3,4,5,6,7,8];

const answer = findMeAnElementsFunkyArray(array, 7, 0);

console.log(answer);

समस्या के पुनरावर्ती समाधान को शामिल करना चाहता था। का आनंद लें

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