leetcode.658(找到 K 个最接近的元素) 二分查找+滑动窗口

题目:
给定一个排序好的数组,两个整数 k 和 x,从数组中找到最靠近 x(两数之差最小)的 k 个数。返回的结果必须要是按升序排好的。如果有两个数与 x 的差值一样,优先选择数值较小的那个数。
示例 1:
输入: [1,2,3,4,5], k=4, x=3
输出: [1,2,3,4]
示例 2:
输入: [1,2,3,4,5], k=4, x=-1
输出: [1,2,3,4]

方法一:常规解法
记录一下我写的又臭又长的代码

class Solution {
public:
    vector<int> findClosestElements(vector<int>& arr, int k, int x) {
        vector<int>res;
        int left=0,right=arr.size()-1;
        int post=0;
        while(left<=right){//找到与目标x最相近的点
            int mid=left+(right-left)/2;
            if(arr[mid]<x){
                left=mid+1;
                post=abs(x-arr[mid])<abs(x-arr[post])?mid:post;
            }
            else if(arr[mid]>x){
                right=mid-1;
                post=abs(x-arr[mid])<abs(x-arr[post])?mid:post;
            }
            else {
                post=mid;
                break;
            }
        }
        res.push_back(arr[post]);k--;
        if(k){
            int i=post-1,j=post+1;
            while(k){//双指针,分别向前和向后寻找合适的点
                if(i>=0&&j<=arr.size()-1&&abs(arr[i]-x)<=abs(arr[j]-x)){
                    res.insert(res.begin(),arr[i]);
                    i--;
                }
                else if(i>=0&&j<=arr.size()-1&&abs(arr[i]-x)>abs(arr[j]-x)){
                    res.push_back(arr[j]);
                    j++;
                }
                else if(i<0){
                     res.push_back(arr[j]);
                    j++;
                }
                else if(j==arr.size()){
                    res.insert(res.begin(),arr[i]);
                    i--;
                }
                k--;
            }
        }
        return res;
    }
};

方法二:二分查找+滑动窗口
看评论区大神的方法:
找到数组中k长度的子数组

class Solution {
public:
    vector<int> findClosestElements(vector<int>& arr, int k, int x) {
         int left = 0;
        int right = arr.size() - k;//保证right后面至少有k-1个数,也就是查找范围是在[0,arr.size()-k],而不是以前的[0,arr.size()-1]
        while(left < right)
        {
            int mid = (left + right) / 2;//mid作为窗口的“头”
            if(x - arr[mid] > arr[mid + k] - x)如果窗口头部元素离x距离比尾部候选元素离x距离更远,那头部元素出窗,尾部元素入窗
            {
                left = mid + 1;
            }
            else
            {
                right = mid;
            }
        }
        return vector<int>(arr.begin() + left, arr.begin() + k + left);
    }
};

你可能感兴趣的:(二分查找)