二分查找 – 数组中的重复元素

huangapple go评论77阅读模式
英文:

Binary-search with duplicate elements in array

问题

以下是您要翻译的内容:

我想要在重复元素的列表中找出是否存在单个元素。

对于这段代码:

private static int findDuplicate(int array[]) {
    int low = 0;
    int high = array.length - 1;

    while (low <= high) {
        int mid = (low + high) >>> 1;
        int midVal = array[mid];
        if (midVal == mid)
            low = mid + 1;
        else
            high = mid - 1;
    }
    return high;
}

它可以找到重复的数字,但我想要找到重复且排序数组中的单个数字。

例如,对于这个 int[] 输入:

[1,1,2,2,3,3,4,5,5]

输出将是 '4'。

或者对于这个 int[] 输入:

[1,1,2,2,3,4,4,5,5,6,6]

输出将是 '3'。

对于这个 int[] 输入:

[1,1,2,7,7,9,9]

输出将是 '2'。

我现在正在使用 Java 进行工作,但任何语言或伪代码都可以。

我知道明显的 O(n) 线性时间遍历方法,但我想看看是否可以通过 O(log n) 二分搜索来实现。

这些元素是经过排序的,并且只重复两次!我知道用简单循环的方法,但我想通过二分搜索来实现。

英文:

I want find if there is a single element in a list of duplicate elements.

For this code

private static int findDuplicate(int array[]) {
    int low = 0;
    int high = array.length - 1;

    while (low &lt;= high) {
        int mid = (low + high) &gt;&gt;&gt; 1;
        int midVal = array[mid];
        if (midVal == mid)
            low = mid + 1;
        else
            high = mid - 1;
    }
    return high;
}

It find the duplicate number but I want to find only the single number
in the duplicate and sorted array.

For example, given this int[] input:

[1,1,2,2,3,3,4,5,5]

Output would be '4'.

Or this int[] input:

[1,1,2,2,3,4,4,5,5,6,6]

Output would be '3'.

In this int[] input:

[1,1,2,7,7,9,9]

Output would be '2'.

I'm working in Java now but any language or psuedo-code is fine.

I know the obvious traversal at O(n) linear time, but I'm trying to see if this is possible via binary search at O(log n) time.

The elements are sorted and only duplicate twice!
I know the way with simple loop but I want to do it by binary search.

答案1

得分: 1

考虑每对连续的两个元素:(不同的2个元素的配对已经用粗体和斜体标出)(注意末尾有一个单独的元素)

(1 1) (2 2) (3 3) <i><b>(4 5) (5 6) (6 7) (7 8) (8)</b></i>

观察到,唯一非重复的元素会形成相应的配对,所有后面的配对都有不同的值,而在那之前的配对具有相同的值。

因此,只需对不同配对的索引进行二分搜索。

该算法也不要求列表是有序的,只要确保恰好有一个元素出现一次,其他所有元素都出现两次,且在连续的索引上。

特殊情况:如果最后一个元素是唯一的,那么所有的配对都会具有相等的值。

英文:

Consider each pair of 2 consecutive elements: (the pairs with 2 elements different are highlighted) (note that there's a stray element at the end)

<pre><code>(1 1) (2 2) (3 3) <i><b>(4 5) (5 6) (6 7) (7 8) (8)</b></i>
</code></pre>

Observe that the only non-duplicated element will make the corresponding pair and all the later pairs have different values, the pairs before that have the same value.

So just binary search for the index of the different pair.

This algorithm also don't require that the list is sorted, only that there's exactly one element which appears once, and all other elements appear twice, in consecutive indices.

Special case: if the last element is the unique one, then all the pairs will have equal values.

答案2

得分: 0

每一对相同值的索引如下所示:

(0,1),
(2,3),
(4,5)
(6,7)

等等。您可以清楚地看到,如果索引是偶数,则与下一个元素进行相似性检查。如果索引是奇数,则可以与前一个值进行相似性检查。
如果这种对称性被打破,您可以向左侧移动,或者如果一切正常,继续向右移动。

伪代码(未经测试):

low = 0,high = arr.length - 1

while low <= high:
    mid = (low + high) / 2
    if mid == 0 || mid == arr.length - 1 || arr[mid] != arr[mid-1] and arr[mid] != arr[mid + 1]: // 如果它们是边界值,或者左右两边的值都不同,那么完成
        return arr[mid]
    if(mid % 2 == 0):
        if arr[mid + 1] != arr[mid]: // 由于偶数索引具有对称性,因此与下一个索引进行检查
            high = mid
        else:
            low = mid + 2
    else:
        if arr[mid - 1] != arr[mid]: // 由于奇数索引具有对称性,因此与前一个索引进行检查
            high = mid
        else:
            low = mid + 1

return -1

注意:上述翻译中的伪代码包含一些特殊字符(例如 <),这些特殊字符可能需要在实际代码中进行调整以保证其正确性。

英文:

Every pair of same values will be like below in terms of indices:

(0,1),
(2,3),
(4,5)
(6,7)

etc. You can clearly see that if index is even, check with next element for similarity. If index is odd, you can check with previous value for similarity.
If this symmetry is broken, you can move towards left side or if everything is ok, keep moving right.

Pseudocode(not tested):

low = 0,high = arr.length - 1

while low &lt;= high:
	mid = (low + high) / 2
	if mid == 0 || mid == arr.length - 1 || arr[mid] != arr[mid-1] and arr[mid] != arr[mid + 1]: // if they are corner values or both left and right values are different, you are done
		return arr[mid]
	if(mid % 2 == 0):
		if arr[mid + 1] != arr[mid]: // check with next index since even for symmetry
			high = mid
		else:
			low = mid + 2
	else:
		if arr[mid - 1] != arr[mid]: // check with prev index since odd for symmetry
			high = mid
		else:
			low = mid + 1

return -1

huangapple
  • 本文由 发表于 2020年10月5日 21:13:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/64209344.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定