658. Find K Closest Elements


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:

  1. The value k is positive and will always be smaller than the length of the sorted array.
  2. Length of the given array is positive and will not exceed 10^4
  3. Absolute value of elements in the array and x will not exceed 10^4

方法1: heap

思路:

维持一个大小为k的heap,遍历一次数组的同时,不断踢掉距离最远的那个数。

Complexity

Time complexity: O(n + nlogk)
Space complexity: O(k)

方法2: two pointer

思路:

从两端开始,remove掉n-k个数字。每一次将双指针中距离比较远的那个消掉并移动。

class Solution {
public:
    vector<int> findClosestElements(vector<int>& arr, int k, int x) {
        if (arr.empty()) return {};
        int left = 0, right = arr.size() - 1;
        
        while (k < arr.size()) {
            if (abs(arr[left] - x) > abs(arr[right] - x) ) {
                left++;
            }
            else {
                right--;
            }
            k++;
        }
        
        vector<int> result(arr.begin() + left, arr.begin() + right + 1);
        return result;
    }
};

// 或者原位删除
class Solution {
public:
    vector<int> findClosestElements(vector<int>& arr, int k, int x) {
        vector<int> res = arr;
        while (res.size() > k) {
            if (x - res.front() <= res.back() - x) {
                res.pop_back();
            } else {
                res.erase(res.begin());
            }
        }
        return res;
    }
};

方法3: binary search + two pointer

思路:

先找到第一个大于或等于x的数,然后用双指针向两端扩展,直到取满k个数字。

Complexity

Time complexity: O(logn + k)
Space complexity: O(k)

class Solution {
public:
    vector<int> findClosestElements(vector<int>& arr, int k, int x) {
        if (arr.empty()) return {};
        int left = 0, right = arr.size() - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (arr[mid] >= x) {
                right = mid;
            }
            else {
                left = mid + 1;
            }
        }
        
        
        left --;
        while (k > 0) {
            if (left >= 0 && right < arr.size()) {
                if (abs(arr[left] - x) <= abs(arr[right] - x) ){
                    left--;
                }
                else {
                    right++;
                }
            }
            else if (left >= 0) {
                left--;
            }
            else  if (right < arr.size()){
                right++;
            }
            k--;
        }
        
        return vector<int>(arr.begin() + left + 1 , arr.begin() + right);
    }
};

方法4: binary search + shrink

官方题解:https://leetcode.com/problems/find-k-closest-elements/solution/

思路:

方法5:binary search + lower bound

小Fu: https://www.youtube.com/watch?v=3ifFNvdfjyg

思路:

看看就好系列。用二分法来找到 长度为k的区间的左端点 。

class Solution {
public:
    vector<int> findClosestElements(vector<int>& arr, int k, int x) {
        if (arr.empty()) return {};
        int left = 0, right = arr.size() - k;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (x - arr[mid] <= arr[mid + k] - x) {
                right = mid;
            }
            else {
                left = mid + 1;
            }
        }
        
        return vector<int> (arr.begin() + left, arr.begin() + left + k);
    }
};

猜你喜欢

转载自blog.csdn.net/wilzxu/article/details/89276251