Given a sorted array arr
, two integers k
and x
, find the k
closest elements to x
in the array. The result should also be sorted in ascending order. If there is a tie, the smaller elements are always preferred.
Example 1:
Input: arr = [1,2,3,4,5], k = 4, x = 3 Output: [1,2,3,4]
Example 2:
Input: arr = [1,2,3,4,5], k = 4, x = -1 Output: [1,2,3,4]
Constraints:
1 <= k <= arr.length
1 <= arr.length <= 10^4
- Absolute value of elements in the array and
x
will not exceed 104
找到K个最接近的元素。
给定一个排序好的数组 arr ,两个整数 k 和 x ,从数组中找到最靠近 x(两数之差最小)的 k 个数。返回的结果必须要是按升序排好的。
整数 a 比整数 b 更接近 x 需要满足:
|a - x| < |b - x| 或者
|a - x| == |b - x| 且 a < b来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-k-closest-elements
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
最优解是二分法。因为 input 数组是有序的而且找的数字一定是在数组中,所以可以用二分法。这个题虽然找的是一个区间(若干个数字),但是由于要找的数字的个数是确定的,所以如果找到了区间的左边界,也就等同于找到了整个区间。这一点很像34题。
关于这个要找的左边界,他的范围是[0, nums.length - K),注意是左闭右开的区间。代码第四行的 right 是在数组下标范围外的。每当找到一个 mid 数字的时候,比较的是 nums[mid] 和 nums[mid + K] 谁与X的差值更小,以决定二分法到底是往左还是往右。这里我们判断的时候不需要添加绝对值符号。我这里分享一个写的很好的帖子说明为什么不需要加绝对值符号。
时间O(logn)
空间O(k) - output array
Java实现
1 class Solution { 2 public List<Integer> findClosestElements(int[] arr, int k, int x) { 3 int left = 0; 4 int right = arr.length - k; 5 while (left < right) { 6 int mid = left + (right - left) / 2; 7 if (x - arr[mid] > arr[mid + k] - x) { 8 left = mid + 1; 9 } else { 10 right = mid; 11 } 12 } 13 List<Integer> res = new ArrayList<>(); 14 for (int i = left; i < left + k; i++) { 15 res.add(arr[i]); 16 } 17 return res; 18 } 19 }
这里我再补充一个很巧妙的双指针的做法。我参考了这个帖子。这个思路很好地利用了 input 数组是排序的条件,同时写起来也不是很难。
时间O(n) - worse case
空间O(k) - output
Java实现
1 class Solution { 2 public List<Integer> findClosestElements(int[] arr, int k, int x) { 3 int left = 0; 4 int right = arr.length - 1; 5 while (left + k <= right) { 6 if (Math.abs(arr[left] - x) > Math.abs(arr[right] - x)) { 7 left++; 8 } else { 9 right--; 10 } 11 } 12 List<Integer> res = new ArrayList<>(); 13 for (int i = left; i < left + k; i++) { 14 res.add(arr[i]); 15 } 16 return res; 17 } 18 }
相关题目