搜索元素的有效方法

时间:2015-12-27 14:56:35

标签: c arrays algorithm sorting search

最近我接受了采访,他们在那里问我" 搜索"问题。
问题是:

  

假设有一个(正)整数数组,其中每个元素与其相邻元素相比为+1-1

     

示例:

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

现在搜索7并返回其位置。

我给出了这个答案:

  

将值存储在临时数组中,对它们进行排序,然后应用二进制搜索。

     

如果找到该元素,则返回其在临时数组中的位置   (如果数字出现两次,则返回第一次出现)

但是,他们似乎并不满意这个答案。

什么是正确的答案?

8 个答案:

答案 0 :(得分:124)

您可以使用通常大于1的步骤进行线性搜索。关键的观察结果是array[i] == 4和7尚未出现,然后7的下一个候选人位于索引i+3。使用while循环重复直接进入下一个可行的候选者。

这是一个略微概括的实现。它会在数组中找到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

答案 1 :(得分:34)

你的方法太复杂了。您不需要检查每个数组元素。第一个值为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 :(得分: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,并且可以使用while循环来确定要检查的下一个索引,具体取决于在索引i + 5找到的值。

虽然这具有复杂度O(n)(渐近复杂度的线性时间),但实际上它比普通线性搜索更好,因为不会访问所有索引。

显然,如果array[i](我们的起点)很奇怪,这一切都会被逆转。

答案 3 :(得分:8)

John Coleman提出的方法很可能是面试官所希望的 如果你愿意变得更复杂,你可以增加预期的跳过长度:
调用目标值 k 。从位置 p 处的第一个元素的值 v 开始,并使用绝对值 av 调用差值k-v dv 。要加速否定搜索,请查看最后一个元素作为位置 o 的另一个值 u :如果dv×du为负数,则存在k(如果出现任何k是可以接受的,你可以像二进制搜索那样缩小索引范围)。如果av + au大于阵列的长度,则k不存在。 (如果dv×du为零,则v或u等于k。)
省略索引有效性:探测序列可能返回到v的(“下一个”)位置,其中k位于中间:o = p + 2*av
如果dv×du为负,则从p + av到o-au找到k(递归地?);
如果它为零,则u等于o 如果du等于dv并且中间的值不是k,或者au超过av,则 或者你失败从p + av到o-au找到k,
p=o; dv=du; av=au;继续探索 (对于'60年代文本的完整回放,请使用Courier查看。我的第一个第二个想法是使用o = p + 2*av - 1,这将排除 du等于dv 。)

答案 4 :(得分:3)

第1步

从第一个元素开始,检查它是否为7.让我们说c是当前位置的索引。所以,最初是c = 0

第2步

如果是7,则找到索引。它是c。如果你已经到达阵列的末尾,那么就爆发了。

第3步

如果不是,则7必须至少在|array[c]-7|个位置,因为每个索引只能添加一个单位。因此,将|array[c]-7|添加到当前索引c,然后再次转到步骤2进行检查。

在最坏的情况下,当存在备用1和-1时,时间复杂度可能达到O(n),但平均情况会很快传递。

答案 5 :(得分:3)

这里我给出了java中的实现...

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;
}

答案 6 :(得分:2)

这是一种分而治之的风格解决方案。以(更多)簿记为代价,我们可以跳过更多元素;而不是从左到右扫描,在中间测试并跳过两个方向。

#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;                                                                     

}

答案 7 :(得分: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);

希望包含针对该问题的递归解决方案。享受