二进制搜索以查找数组的K个最近元素

时间:2019-04-11 23:27:07

标签: java

我正在从问题Find K Closest Elements - LeetCode的leetcode学习二进制搜索

  

给出一个有序的数组,两个整数kx,在数组中找到最接近k的{​​{1}}个元素。结果也应按升序排序。如果有平局,则总是首选较小的元素。

     

示例1:

x
     

示例2:

Input: [1,2,3,4,5], k=4, x=3
Output: [1,2,3,4]
     

注意:

     
      
  1. 值k为正,并且始终小于已排序数组的长度。
  2.   
  3. 给定数组的长度为正,不会超过104
  4.   
  5. 数组和x中元素的绝对值不超过104
  6.   

这是官方解决方案:

  方法2:二进制搜索和两个指针      

算法

     

原始数组已排序,因此我们可以通过以下步骤利用此优势。

     
      
  1. 如果目标Input: [1,2,3,4,5], k=4, x=-1 Output: [1,2,3,4] 小于或等于排序数组中的第一个元素,则前x个元素就是结果。

  2.   
  3. 类似地,如果目标k大于或等于排序数组中的最后一个元素,则最后的x个元素就是结果。

  4.   
  5. 否则,我们可以使用二进制搜索来找到元素的k,该元素等于(当此列表具有index时)或比x大一点(当此列表没有它时)。然后将x设置在其low的左侧k-1位置,并将high设置在此k-1的右侧index的位置。所需的k数必须在此范围内[index-k-1,index + k-1]。因此,我们可以使用以下规则缩小此范围以获取结果。

         
        
    • 如果low到达最低索引0low元素比x更接近high,则减小{{ 1}}索引。

    •   
    • 如果high到达最高索引high或比arr.size()-1元素更接近x,请增加low索引。

    •   
    • 当[low,high]中恰好有k个元素(其子列表是结果)时,循环结束。

    •   
  6.   

实施

low

我对实施有3个问题

  1. 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]
  2. [index-k-1],因为将低设置为if (low < 0 || (x - arr.get(low)) <= (arr.get(high) - x)) #2????,并且会向前增加,是否有必要像low = Math.max(0, index - k - 1),一样检查low < 0
  3. else if (high > arr.size() - 1 || (x - arr.get(low)) > (arr.get(high) - x)) #????,它比while (high - low > k - 1)有什么好处?

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 < 0high > arr.size() - 1是不必要的检查。您可以将其删除。

对于问题3:
在整数比较中,high - low > k - 1等于high - low >= k。 这只是两种不同的编程习惯,请选择一种。

希望对您有所帮助,如果还有其他问题,请发表评论。 :)