按值和索引搜索数组

时间:2018-10-06 10:50:44

标签: java arrays search binary-search

我有一个整数排序的数组,要在其上执行搜索。该数组可以具有重复的值。 如果我搜索重复的元素,则它应返回该元素的第一个实例的索引

如果我使用Arrays.binarySearch(),则不一定给出所搜索元素的第一个实例的索引。可以看到示例here

int[] A = {10,20,21,24,24,24,24,24,30,40,45} ;
int idx = Arrays.binarySearch(A,24) ;

idx将为5。我希望它是3。我通过使类Pair像这样解决了这个问题:

class Pair implements Comparable<Pair>
{
    int value, index ;
    Pair(int v,int i)
    {
        this.value = v ;
        this.index = i ;
    }
    @Override
    public int compareTo(Pair p)
    {
        if(p.value<this.value)
            return 1 ;
        else if(p.value>this.value)
            return -1 ;
        else 
        {
            if(p.index<this.index)
                return 1 ;
            else if(p.index>this.index)
                return -1 ;
            else return 0 ;
        }
    }
}

Collections.binarySearch(new Pair(24,Integer.MIN_VALUE))搜索(对于Pair的列表)时,将返回3。 代码如下:

int[] A = {10,20,21,24,24,24,24,24,30,40,45} ;

        List<Pair> L = new ArrayList<Pair>() ;

        for(int i=0;i<A.length;i++)
        {
            L.add(new Pair(A[i],i)) ;
        }
        int idx = Collections.binarySearch(L,new Pair(24,Integer.MIN_VALUE)) ;
        if(idx<0) idx = -idx-1 ;
        System.out.println(idx) ;

Pair的工作方式如下: 它具有两个变量valueindex,分别是已排序数组元素的值和数组元素的索引。 compareTo方法被重写,以允许Collections.binarySearch()执行比较。可以这样定义比较:

  • 如果当前value更大或更小,则顺序由value决定。
  • 如果value相同,则使用index确定顺序。

我的问题是,这能以一种不太混乱的方式完成吗?任何较短的内容,将不胜感激!

6 个答案:

答案 0 :(得分:3)

看看下面的代码。对原始二进制搜索代码进行了更改:lr分别为左和右范围

public static int binarySearch(int[] arr, int num, int l,int r) {
    int mid = (l+r)/2;
    if(arr[mid] == num && (mid>0&& arr[mid-1]!=num) || mid==0) {            
        return mid;
    }       
    else if(arr[mid] > num || (mid > l && arr[mid] == num && arr[mid-1] == num)) {
        return binarySearch(arr, num, l, mid);
    }else {
        return binarySearch(arr, num, mid, r);
    }
}

答案 1 :(得分:1)

如果您的问题只是处理数组A,则可以使用下面的代码找到第一个索引:

    int[] A = { 10, 20, 21, 24, 24, 24, 24, 24, 30, 40, 45 };
    // key is a[i], value is the index
    Map<Integer, Integer> hmap = new HashMap<Integer, Integer>();

    for (int i = 0; i < A.length; i++) {
        hmap.putIfAbsent(A[i], i);
    }

如果已经存在一个数字,则我们不会增加i的值,因为我们需要重复数字的第一个索引。这样一来,重复编号的第一个索引将始终保持不变。

现在要获取索引,我们需要做的只是hmap.get(24)

答案 2 :(得分:1)

只是一个骇人听闻的解决方案。

double[] A = { 10, 20, 21, 24, 24, 24, 24, 24, 30, 40, 45 };
int key = 24;
int idx = -(Arrays.binarySearch(A, key - 0.5) + 1);
if (A[idx] != key)
    System.out.println("Key not exist!");
else
    System.out.println("First occurance of key is " + idx);

二进制搜索正在查找数字的出现,如果未找到该数字,则将数字添加到排序列表中。

答案 3 :(得分:1)

为什么不能从二分搜索线性搜索中获得最大收益?使用二进制搜索获取数字的 出现位置的索引,然后从那里线性搜索以找到 first 出现的位置:

int[] A = { 10, 20, 21, 24, 24, 24, 24, 24, 30, 40, 45 };
int key = 24;
int idx = Arrays.binarySearch(A, key);
while (idx > 0) {
    if (A[idx - 1] != key)
        break;
    --idx;
}
if (idx < 0)
    System.out.println("Key " + key + " not found");
else
    System.out.println("First index of key " + key + " is " + idx);

答案 4 :(得分:0)

您可以尝试创建自己的二进制搜索功能,除非第一次出现我们要搜索的数字(之前的数字不同),否则它不会停止搜索

尝试此二进制搜索功能:

public static int binarySearch(int[] arr,int x)
{
    int maxi=arr.length-1;
    int mini=0;
    int mid;
    while(mini<=maxi)
    {
        mid=(maxi+mini)/2;
        if(arr[mid]==x&&(mid==0||arr[mid-1]!=x))
        {
            return mid;
        }
        else if(arr[mid]<x)
        {
            mini=mid+1;
        }
        else
        {
            maxi=mid-1;
        }
    }
    return -1;
}

答案 5 :(得分:0)

只需找到索引,然后向后搜索即可找到第一个索引(如果存在)。这将是O(log(n) + m);其中m是在数组中找到此元素的次数(该元素在数组中重复的次数)。

 private static int findFirstIndex(List<Pair> pairs, Pair search) {
    int idx = Collections.binarySearch(pairs, search);
    if (idx < 0) {
        return idx = -idx - 1;
    }

    for (; idx > 1; --idx) {
        if (pairs.get(idx - 1).compareTo(pairs.get(idx)) != 0) {
            return idx;
        }
    }

    return idx;
}