[英]How to use Binary Search to find duplicates in sorted array?
I am attempting to expand a function to find the number of integer matches through Binary Search by resetting the high variable, but it gets stuck in a loop. 我试图通过重置高变量来扩展通过二进制搜索找到整数匹配数的函数,但是它陷入了循环。 I am guessing a workaround would be to duplicate this function to obtain the last index to determine the number of matches, but I do not think this would be such an elegant solution. 我猜一种解决方法是复制此函数以获得最后一个索引来确定匹配数,但是我认为这不是一个很好的解决方案。
From this: 由此:
public static Matches findMatches(int[] values, int query) {
int firstMatchIndex = -1;
int lastMatchIndex = -1;
int numberOfMatches = 0;
int low = 0;
int mid = 0;
int high = values[values.length - 1];
boolean searchFirst = false;
while (low <= high){
mid = (low + high)/2;
if (values[mid] == query && firstMatchIndex == -1){
firstMatchIndex = mid;
if (searchFirst){
high = mid - 1;
searchFirst = false;
} else {
low = mid + 1;
}
} else if (query < values[mid]){
high = mid - 1;
} else {
low = mid + 1;
}
}
if (firstMatchIndex != -1) { // First match index is set
return new Matches(firstMatchIndex, numberOfMatches);
}
else { // First match index is not set
return new Matches(-1, 0);
}
}
To something like this: 对于这样的事情:
public static Matches findMatches(int[] values, int query) {
int firstMatchIndex = -1;
int lastMatchIndex = -1;
int numberOfMatches = 0;
int low = 0;
int mid = 0;
int high = values[values.length - 1];
boolean searchFirst = false;
while (low <= high){
mid = (low + high)/2;
if (values[mid] == query && firstMatchIndex == -1){
firstMatchIndex = mid;
if (searchFirst){
high = values[values.length - 1]; // This is stuck in a loop
searchFirst = false;
}
} else if (values[mid] == query && lastMatchIndex == -1){
lastMatchIndex = mid;
if (!searchFirst){
high = mid - 1;
} else {
low = mid + 1;
}
} else if (query < values[mid]){
high = mid - 1;
} else {
low = mid + 1;
}
}
if (firstMatchIndex != -1) { // First match index is set
return new Matches(firstMatchIndex, numberOfMatches);
}
else { // First match index is not set
return new Matches(-1, 0);
}
}
There is a problem with your code: 您的代码有问题:
high = values[values.length - 1];
should be 应该
high = values.length - 1;
Also you do not need variables like numberOfMatches and searchFirst, we can have rather simple solution. 另外,您不需要numberOfMatches和searchFirst之类的变量,我们可以有一个非常简单的解决方案。
Now coming to the problem,I understand what you want I think Binary Search is appropriate for such query. 现在来解决这个问题,我了解您想要什么,我认为二进制搜索适合这种查询。
The Best way to do the required is once a match is found you just go forward and backward from that index until a mismatch occurs and this would be both elegant and efficient in calculating the firstMatchIndex and numberOfMatches. 达到要求的最佳方法是, 一旦找到匹配项,您就从该索引向前或向后前进,直到发生不匹配为止,这在计算firstMatchIndex和numberOfMatches方面既优雅又有效。
So your function should be: 因此,您的功能应为:
public static Matches findMatches(int[] values, int query)
{
int firstMatchIndex = -1,lastMatchIndex=-1;
int low = 0,mid = 0,high = values.length - 1;
while (low <= high)
{
mid = (low + high)/2;
if(values[mid]==query)
{
lastMatchIndex=mid;
firstMatchIndex=mid;
while(lastMatchIndex+1<values.length&&values[lastMatchIndex+1]==query)
lastMatchIndex++;
while(firstMatchIndex-1>=0&&values[firstMatchIndex-1]==query)
firstMatchIndex--;
return new Matches(firstMatchIndex,lastMatchIndex-firstMatchIndex+1);
}
else if(values[mid]>query)
high=mid-1;
else low=mid+1;
}
return new Matches(-1,0);
}
Couldn't you just use something like a set to find duplicates? 您不能只使用set来查找重复项吗?
Something like this: 像这样:
package example;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
public class DuplicatesExample {
public static void main(String[] args) {
String[] strings = { "one", "two", "two", "three", "four", "five", "six", "six" };
List<String> dups = getDups(strings);
System.out.println("DUPLICATES:");
for(String str : dups) {
System.out.println("\t" + str);
}
}
private static List<String> getDups(String[] strings) {
ArrayList<String> rtn = new ArrayList<String>();
HashSet<String> set = new HashSet<>();
for (String str : strings) {
boolean added = set.add(str);
if (added == false ) {
rtn.add(str);
}
}
return rtn;
}
}
Output: 输出:
DUPLICATES:
two
six
I have split your problems into two parts - using binary search to find a number and counting the number of matches. 我将您的问题分为两部分-使用二进制搜索查找数字并计算匹配数。 The first part is resolved by the search function while the second part is resolved by the findMatches function: 第一部分由搜索功能解决,而第二部分由findMatches函数解决:
public static Matches findMatches(int[] values, int query) {
int leftIndex = -1;
int rightIndex = -1;
int high = values.length - 1;
int matchedIndex = search(values, 0, high, query);
//if at least one match
if (matchedIndex != -1) {
//decrement upper bound of left array
int leftHigh = matchedIndex - 1;
//increment lower bound of right array
int rightLow = matchedIndex + 1;
//loop until no more duplicates in left array
while (true) {
int leftMatchedIndex = search(values, 0, leftHigh, query);
//if duplicate found
if (leftMatchedIndex != -1) {
leftIndex = leftMatchedIndex;
//decrement upper bound of left array
leftHigh = leftMatchedIndex - 1;
} else {
break;
}
}
//loop until no more duplicates in right array
while(true){
int rightMatchedIndex = search(values, rightLow, high, query);
//if duplicate found
if(rightMatchedIndex != -1){
rightIndex = rightMatchedIndex;
//increment lower bound of right array
rightLow = rightMatchedIndex + 1;
} else{
break;
}
}
return new Matches(matchedIndex, rightIndex - leftIndex + 1);
}
return new Matches(-1, 0);
}
private static int search(int[] values, int low, int high, int query) {
while (low <= high) {
int mid = (low + high) / 2;
if (values[mid] == query) {
return mid;
} else if (query < values[mid]) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
I found a solution after correcting a mistake with resetting high variable that caused an infinite loop. 在更正导致无限循环的高变量重置错误后,我找到了解决方案。
public static Matches findMatches(int[] values, int query) {
int firstMatchIndex = -1;
int lastMatchIndex = -1;
int numberOfMatches = 0;
int low = 0;
int mid = 0;
int high = values.length - 1;
while (low <= high){
mid = (low + high)/2;
if (values[mid] == query && firstMatchIndex == -1){
firstMatchIndex = mid;
numberOfMatches++;
high = values.length - 1;
low = mid;
} else if (values[mid] == query && (lastMatchIndex == -1 || lastMatchIndex != -1)){
lastMatchIndex = mid;
numberOfMatches++;
if (query < values[mid]){
high = mid - 1;
} else {
low = mid + 1;
}
} else if (query < values[mid]){
high = mid - 1;
} else {
low = mid + 1;
}
}
if (firstMatchIndex != -1) { // First match index is set
return new Matches(firstMatchIndex, numberOfMatches);
}
else { // First match index is not set
return new Matches(-1, 0);
}
}
Not having any knowledge of the data other than sorted a priori is tough. 除了先验排序以外,对数据一无所知是很困难的。 See this: Binary Search O(log n) algorithm to find duplicate in sequential list? 请参阅以下内容: 二进制搜索O(log n)算法在顺序列表中查找重复项?
This will find the first index of duplicates of k in a sorted array. 这将在排序数组中找到k的重复项的第一个索引。 Of course this is related to knowing the value of duplicate first but very useful when it is known. 当然,这与首先知道重复项的值有关,但在知道重复项的值时非常有用。
public static int searchFirstIndexOfK(int[] A, int k) {
int left = 0, right = A.length - 1, result = -1;
// [left : right] is the candidate set.
while (left <= right) {
int mid = left + ((right - left) >>> 1); // left + right >>> 1;
if (A[mid] > k) {
right = mid - 1;
} else if (A[mid] == k) {
result = mid;
right = mid - 1; // Nothing to the right of mid can be
// solution.
} else { // A[mid] < k
left = mid + 1;
}
}
return result;
}
This will find a dupe in log(n) time but is fragile in that the data must be sorted as well as increasing by 1 and in the range 1..n. 这会发现log(n)时间上的重复,但是它很脆弱,因为必须对数据进行排序并将其增加1,且范围为1..n。
static int findeDupe(int[] array) {
int low = 0;
int high = array.length - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
if (array[mid] == mid) {
low = mid + 1;
} else {
high = mid - 1;
}
}
System.out.println("returning" + high);
return high;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.