我有代码搜索已排序的数组并返回第一次出现的k的索引。 我想知道是否可以使用
编写此代码while(left<right)
而不是
while(left<=right)
以下是完整代码:
public static int searchFirstOfK(List<Integer> A, int k) {
int left = 0, right = A.size() - 1, result = -1;
// A.subList(left, right + 1) is the candidate set.
while (left <= right) {
int mid = left + ((right - left) / 2);
if (A.get(mid) > k) {
right = mid - 1;
} else if (A.get(mid) == k) {
result = mid;
// Nothing to the right of mid can be the first occurrence of k.
right = mid - 1;
} else { // A.get(mid) < k
left = mid + 1;
}
}
return result;
}
我如何知道何时使用左边小于或等于右边,或者只是使用左边小于右边。
答案 0 :(得分:2)
简单地说没有。
考虑数组只有一个元素的情况,即{0}
,并且要搜索的元素也是0
。
在这种情况下,left == right
,但如果您的条件为while(left<right)
,则searchFirstOfK
将返回-1
。
此答案取决于发布的代码。如果我们正在谈论替代方案以便我们可以使用while(left<right)
那么Matt Timmermans的答案是正确的,并且是一种更好的方法。
下面是Matt的comparison(OP - 我们称之为Normal Binary)和Matt Timmermans(让我们称之为Optimized Binary)方法,列出包含0到5000000之间值的列表:
答案 1 :(得分:2)
基于对另一个二进制搜索问题的答案:How can I simplify this working Binary Search code in C?
如果要查找第一次出现的位置,则在找到匹配的元素时无法停止。您的搜索应该如下所示(当然这假定列表已排序):
int findFirst(List<Integer> list, int valueToFind)
{
int pos=0;
int limit=list.size();
while(pos<limit)
{
int testpos = pos+((limit-pos)>>1);
if (list.get(testpos)<valueToFind)
pos=testpos+1;
else
limit=testpos;
}
if (pos < list.size() && list.get(pos)==valueToFind)
return pos;
else
return -1;
}
请注意,我们每次迭代只需要进行一次比较。二进制搜索找到所有前面的元素小于valueToFind
并且所有以下元素都大于或等于的唯一位置,然后然后它检查您的值是否为&#39;正在寻找的确实存在。
链接的答案强调了以这种方式编写二进制搜索的几个优点。
答案 2 :(得分:0)
这是一个非常有趣的问题。事情就是有一种方法可以让你的二进制搜索始终正确。问题在于确定正确的范围并避免单个元素突出行为。
while(left+1<right)
{
m = (left+right)/2;
if(check condition is true)
left = m;
else
right = m;
}
唯一要记住的关键是你总是将左边视为最不满意元素的最小条件,并且是满足元素的最大条件。这样你就不会被困住。一旦你通过这种方法理解了范围划分,你就不会在二进制搜索中失败。
上面的初始化将为您提供满足元素的最大条件。
通过更改初始化,您可以获得各种元素(例如满足元素的小条件)。