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
Solution #1, O(logN + K)
class Solution {
    public List<Integer> findClosestElements(int[] arr, int k, int x) {
        int left = findClosest(arr, x);
        int right = left + 1;
        int n = arr.length;
        if (left == -1) {
            right = k;
        }else if (left == n) {
            right = n;
            left = n - k - 1;
        }else {
            while (k > 0) {
                if (left >= 0 && right < n) {
                    if (x - arr[left] > arr[right] - x) {
                        right++;
                    }else {
                        left--;
                    }
                }else if (left >= 0) {
                    left--;
                }else {
                    right++;
                }
                k--;
            }
        }
        left++;
        right--;
        
        List<Integer> rt = new ArrayList<>();
        for (int i = left; i <= right; i++) {
            rt.add(arr[i]);
        }
        
        return rt;
    }
    
    private int findClosest(int[] arr, int x) {
        int left = 0, right = arr.length - 1;
        
        while (left <= right) {
            int mid = (left + right) / 2;
            if (mid < arr.length - 1 && arr[mid] <= x && arr[mid + 1] > x) return mid;
            if (arr[mid] > x) {
                right = mid - 1;
            }else {
                left = mid + 1;
            }
        }
        
        return left;
    }
}
Solution #2, O(logN + K),ref:https://leetcode.com/problems/find-k-closest-elements/discuss/106419/O(log-n)-Java-1-line-O(log(n)-+-k)-Ruby
二分查找subarray的起点,用反证法可以证明此算法的正确性
class Solution {
    public List<Integer> findClosestElements(int[] arr, int k, int x) {
        int left = 0, right = arr.length - k;
        
        while (left < right) {
            int mid = (left + right) / 2;
            if (x - arr[mid] <= arr[mid + k] - x) {
                right = mid;
            }else {
                left = mid + 1;
            }
        }
        
        List<Integer> rt = new ArrayList<>();
        for (int i = 0; i < k; i++) {
            rt.add(arr[left + i]);
        }
        
        return rt;
    }
}
 
No comments:
Post a Comment