Find K Closest Elements

Given a sorted array, two integers k and x, find the k closest elements to xin 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 104
  3. Absolute value of elements in the array and x will not exceed 104

1.解析

题目大意,求解跟x差值最小的k个元素,所给的序列是递增的。

2.分析

题目整体上看,还是比较简单的。下面是我所想到的解法,核心思想:利用stl库的lower_bound函数查找序列的第一个大于或等于x的元素的位置,然后以该位置作为起点,向左右两边寻找。但要注意的一个问题是,左边当到达begin的位置时,要单独标记一下,因为迭代器begin往前面的一个位置时未知的,不想end迭代器。所以我利用一个flag布尔变量标记左边到达begin位置。

class Solution {
public:
    vector<int> findClosestElements(vector<int>& arr, int k, int x) {
        auto it = lower_bound(arr.begin(), arr.end(), x); //查找第一个大于或等于x的值
        if (it == arr.end()) return vector<int>{arr.end() - k, arr.end()};
        else if (it == arr.begin()) return vector<int>{arr.begin(), arr.begin() + k};
        
        vector<int> res;
        bool flag = false;
        auto cur = it;
        cur--;
        while (k-- > 0){
            if (it == arr.end()){ //右边到达边界,则只需依次取左边的元素
                res.push_back(*cur); --cur;
                continue;
            }
            else if (flag) { //左边到达边界,则只需依次取右边的元素
                res.push_back(*it); ++it;
                continue;
            }
            int next_diff = *it - x;
            int pre_diff = x - *cur;
            if (pre_diff > next_diff){ //若右边的元素与x的差值小,则取右边的元素,并将指针往右移一个位置
                res.push_back(*it);
                ++it; 
            }
            else{ //若左边的元素与x的差值小,则取左边的元素,并将指针往左移一个位置
                res.push_back(*cur);
                if (cur == arr.begin()) flag = true; //到达首部
                else --cur;
            }
        }
        sort(res.begin(), res.end()); //所取到的结果是从左右两边取得元素,所以要重新排一下序
        return res;
    }
};

下面这种解法,参考@Grandyang博主的博客。很巧妙,核心思想:从左右两边的边界开始,如果左边与x的差值要小于或等于右边的(题目中要求,如差值一样,取元素的较小值),则去掉右边界的元素;若反之, 去掉左边的元素.......直到数组中的只剩下k个元素,即为我们所求的,确实很精辟。

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

[1]https://www.cnblogs.com/grandyang/p/7519466.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值