我正在从问题Find K Closest Elements - LeetCode的leetcode学习二进制搜索
给出一个有序的数组,两个整数
k
和x
,在数组中找到最接近k
的{{1}}个元素。结果也应按升序排序。如果有平局,则总是首选较小的元素。示例1:
x
示例2:
Input: [1,2,3,4,5], k=4, x=3 Output: [1,2,3,4]
注意:
- 值k为正,并且始终小于已排序数组的长度。
- 给定数组的长度为正,不会超过104
- 数组和x中元素的绝对值不超过104
这是官方解决方案:
方法2:二进制搜索和两个指针算法
原始数组已排序,因此我们可以通过以下步骤利用此优势。
如果目标
Input: [1,2,3,4,5], k=4, x=-1 Output: [1,2,3,4]
小于或等于排序数组中的第一个元素,则前x
个元素就是结果。类似地,如果目标
k
大于或等于排序数组中的最后一个元素,则最后的x
个元素就是结果。否则,我们可以使用二进制搜索来找到元素的
k
,该元素等于(当此列表具有index
时)或比x
大一点(当此列表没有它时)。然后将x
设置在其low
的左侧k-1
位置,并将high
设置在此k-1
的右侧index
的位置。所需的k数必须在此范围内[index-k-1,index + k-1]。因此,我们可以使用以下规则缩小此范围以获取结果。
如果
low
到达最低索引0
或low
元素比x
更接近high
,则减小{{ 1}}索引。如果
high
到达最高索引high
或比arr.size()-1
元素更接近x
,请增加low
索引。当[low,high]中恰好有k个元素(其子列表是结果)时,循环结束。
实施
low
我对实施有3个问题
public class Solution {
public List<Integer> findClosestElements(List<Integer> arr, int k, int x) {
int n = arr.size();
if (x <= arr.get(0)) {
return arr.subList(0, k);
} else if (arr.get(n - 1) <= x) {
return arr.subList(n - k, n);
} else {
int index = Collections.binarySearch(arr, x);
if (index < 0)
index = -index - 1;
int low = Math.max(0, index - k - 1), high = Math.min(arr.size() - 1, index + k - 1); #1????
while (high - low > k - 1) {
if (low < 0 || (x - arr.get(low)) <= (arr.get(high) - x)) #2????
high--;
else if (high > arr.size() - 1 || (x - arr.get(low)) > (arr.get(high) - x)) #????
low++;
else
System.out.println("unhandled case: " + low + " " + high);
}
return arr.subList(low, high + 1);
}
}
}
,我假设它为low = Math.max(0, index - k - 1)
,因为低位的左位置是low = Math.max(0, index - k - 1)
,而不是[index -k +1]
。 [index-k-1]
,因为将低设置为if (low < 0 || (x - arr.get(low)) <= (arr.get(high) - x)) #2????
,并且会向前增加,是否有必要像low = Math.max(0, index - k - 1),
一样检查low < 0
else if (high > arr.size() - 1 || (x - arr.get(low)) > (arr.get(high) - x)) #????
,它比while (high - low > k - 1)
有什么好处?答案 0 :(得分:2)
首先,我想说的是,这是我在Leetcode中阅读的质量最低的官方解决方案,正如您所说,它确实在该解决方案中有很多缺陷。我将一一解释。
对于问题1:
您在这里是对的,我们应该将Math.max(0, index - k - 1)
更改为Math.max(0, index - k)
,而不是Math.max(0, index - k + 1)
。因为当目标数字x
不在数组中而剩下的k
是我们想要的结果时,我们应该从index - k
开始。
例如:
Input: [1,2,3,10,11], k=4, x=2
索引是3
,我们应该从index-k=2
对于问题2:
您是正确的,此处low < 0
和high > arr.size() - 1
是不必要的检查。您可以将其删除。
对于问题3:
在整数比较中,high - low > k - 1
等于high - low >= k
。
这只是两种不同的编程习惯,请选择一种。
希望对您有所帮助,如果还有其他问题,请发表评论。 :)