658-find-k-closest-elements
Question
https://leetcode.com/problems/find-k-closest-elements/description/
Given a sorted array, 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: [1,2,3,4,5], k=4, x=3
Output: [1,2,3,4]
Example 2:
Input: [1,2,3,4,5], k=4, x=-1
Output: [1,2,3,4]
Note:
- The value k is positive and will always be smaller than the length of the sorted array.
- Length of the given array is positive and will not exceed 104
- Absolute value of elements in the array and x will not exceed 104
Thought Process
- Binary Search and Expand Window
- Locate the closest element using modified binary search
- Scan left and right to find the window of length k, where it contains the closest elements to x
- Time complexity O(nlogn)
- Space complexity O(1)
- Modified Binary Search
- To find the range of k sequence, we know the sequence has to start ranging from 0 to n - k, where n is length of the array
- We use two pointers, lo and hi to narrow our search for the starting point
- Then we compare x - arr[mid] with arr[mid + k] - x, if first difference is greater than the second's, mid cannot be our starting point, so we move lo to mid + 1
- Time complexity O(logn)
- Space complexity O(1)
Solution
class Solution {
public List<Integer> findClosestElements(int[] arr, int k, int x) {
int id = binarySearch(arr, x);
int l = id, r = id, n = arr.length;
while (--k > 0) {
if (l == 0) r++;
else if (r == n - 1) l--;
else if (Math.abs(arr[l - 1] - x) > Math.abs(arr[r + 1] - x)) r++;
else l--;
}
List<Integer> res = new ArrayList<>(k);
while (l <= r) res.add(arr[l++]);
return res;
}
private int binarySearch(int[] arr, int x) {
int n = arr.length;
int i = Arrays.binarySearch(arr, x);
if (i < 0) {
i = - (i + 1);
int leftDiff = i > 0 ? x - arr[i - 1] : Integer.MAX_VALUE;
int rightDiff = i < n ? arr[i] - x : Integer.MAX_VALUE;
i = leftDiff < rightDiff ? i - 1 : i;
}
return i;
}
}
class Solution {
public List<Integer> findClosestElements(int[] arr, int k, int x) {
int lo = 0, hi = arr.length - k;
while (lo < hi) {
int mi = lo + (hi - lo) / 2;
if (x - arr[mi] > arr[mi + k] - x) lo = mi + 1;
else hi = mi;
}
List<Integer> res = new ArrayList<>(k);
while (k-- > 0) res.add(arr[lo++]);
return res;
}
}