二分查找_LeetCode找到K个最接近的元素

               二分查找_LeetCode找到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]
 

说明:

k 的值为正数,且总是小于给定排序数组的长度。
数组不为空,且长度不超过 104
数组里的每个元素与 x 的绝对值不超过 104

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-k-closest-elements

解法1:遍历排序

利用sort函数,加上lambda表达式可以方便的按照每个元素与目标x的差值排序。

class Solution {
public:
  
    vector<int> findClosestElements(vector<int>& arr, int k, int x) {
       
        sort(arr.begin(),arr.end(),[=](int v1,int v2){
            if(abs(v1 - x) < abs(v2 - x))
            return true;
            else if(abs(v1 - x) == abs(v2 - x))
            {
            //如果差值相等,那么数字小的排前面
                if(v1 < v2) return true;
                else return false;
            }
            else 
            return false;
        });
        //按照题目要求返回升序序列
        vector<int> vec(arr.begin(),arr.begin()+k);
        sort(vec.begin(),vec.end());
        return vec;

    }
};

时间复杂度O(n)
在这里插入图片描述

解法二:二分查找+滑动窗口

这个方法非常的巧妙,同时也不好理解,先看下面这个图。
在这里插入图片描述
  这种解法就是利用滑动窗口的思想,最终目的就是找到一个最满足题意的窗口,而且本身数组就是升序的,所以就可以把寻找范围的问题转化为寻找最终窗口的左边界的问题。这就是想到二分查找的原因,二分查找的关键在于找到合适的条件来二分区间,缩小搜索范围。这里的左边界初始搜索区间为[0, arr.size()-k];
  这里的关键代码if(x - arr[mid] > arr[mid + k] - x),当前窗口为[mid, mid+k-1],右边的窗口为[mid+1, mid+k],因为这两个窗口的其他部分都是重合的,所以这里就用当前窗口的左边界和X的差值与右边窗口的右边界与X的差值对比。如果结果是大于,那么说明右边窗口更靠近X(右边窗口中每个元素与x的差值的绝对值之和更小),那么把当前窗口向右移动,left=mid+1;最后left=right,否则向左移动(包括差值相等的情况),然后循环搜索。就找到了最终窗口的左边界。

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

时间复杂度O(logn+k)
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值