我有一个整数排序的数组,要在其上执行搜索。该数组可以具有重复的值。 如果我搜索重复的元素,则它应返回该元素的第一个实例的索引。
如果我使用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
的工作方式如下:
它具有两个变量value
和index
,分别是已排序数组元素的值和数组元素的索引。 compareTo
方法被重写,以允许Collections.binarySearch()
执行比较。可以这样定义比较:
value
更大或更小,则顺序由value
决定。value
相同,则使用index
确定顺序。我的问题是,这能以一种不太混乱的方式完成吗?任何较短的内容,将不胜感激!
答案 0 :(得分:3)
看看下面的代码。对原始二进制搜索代码进行了更改:l
和r
分别为左和右范围
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;
}