Leetcode 658. 找到 K 个最接近的元素 题解

题目链接:https://leetcode-cn.com/problems/find-k-closest-elements/
在这里插入图片描述
二分 + 双指针

第一步二分,找到离 x 最近的元素(维护了两个变量 bi 和 ls,标记每次找到的大于 x 的最小元素和小于 x 的最大元素,这样二分结束后可根据这两个变量确定选取哪一个指针指向的元素)

第二步双指针,以第一步找到的元素为中心,向两边扩展 k 个位置,然后遍历缩小,直到双指针之间正好相差 k 个元素

需要处理的边界问题在于,有两组满足条件的结果时,要取索引较小的,即比如我要在[1, 2, 3, 5, 6, 7]中找离 4 最近的5个元素,[1,2,3,5,6]和[2,3,5,6,7]都满足最优,此时要取[1,2,3,5,6]。所以在第二步的双指针法中,要尽可能的多挪动右指针,所以判等要归到右指针条件下。

代码如下:

class Solution {
public:
    vector<int> findClosestElements(vector<int>& arr, int k, int x) {
        vector<int> res;
        if(x <= arr[0]) {
            for(int i = 0; i < k; i++) {
                res.push_back(arr[i]);
            }
            return res;
        } else if(x >= arr[arr.size() - 1]) {
            for(int i = arr.size() - k; i < arr.size(); i++) {
                res.push_back(arr[i]);
            }
            return res;
        } else {
            //printf("二分来啦!\n");
            //二分 + 双指针
            // 1.二分找下标
            int l = 0, r = arr.size() - 1;
            int bi = INT_MAX, ls = INT_MIN;
            int pos = -1;
            while(l <= r) {
                int mid = (l + r) / 2;
                if(arr[mid] == x) {
                    pos = mid;
                    break;
                } else if(arr[mid] > x) {
                    bi = min(bi, arr[mid] - x);
                    r--;
                } else {
                    ls = max(ls, arr[mid] - x);
                    l++;
                }
                //printf("l = %d, r = %d, bi = %d, ls = %d\n", l, r, bi, ls);
            }
            
			//取离 x 更近的元素
			if(pos == -1) {
                if(bi + ls >= 0) {
                    pos = r;
                } else {
                    pos = l; 
                }
            }
            
            
            printf("pos = %d\n",pos);
            l = pos - k + 1, r = pos + k - 1;
            printf("l = %d, r = %d\n", l, r);
            while(r - l >= k) {
                while(l < 0) {
                    l++;
                }
                while(r >= arr.size()) {
                    r--;
                }
                printf("l = %d, r = %d\n", l, r);
                if(r - l + 1 == k) {
                    break;
                } else {
                	//判等要放在 else 中,为了尽可能挪动右指针
                    if(x - arr[l] > arr[r] - x) {
                        l++;
                    } else {
                        r--;
                    }
                }
                printf("l = %d, r = %d\n", l, r);
            }
            for(int i = l; i <= r; i++) {
                res.push_back(arr[i]);
            }
        }
        return res;
    }
};

猜你喜欢

转载自blog.csdn.net/weixin_42396397/article/details/105948324