找到K个最接近的元素
658. 找到 K 个最接近的元素 - 力扣(LeetCode)
Solution
逆向思维,首先知道的是原数组已经排好序了,如果正向去找的话,就得从最接近x的元素开始找,首先使用二分查找去找数组中最接近x的元素,然后用背向双指针去一个一个找,然后对结果数组进行排序,这是比较直接的一个想法。
但是使用逆向思维的话,首先可以发现,按正向的方式去寻找的话,答案一定是原数组中连续的一部分,那么就可以从两端去寻找n-k个不接近x的元素,剩下的就是答案。
- 初始时,整个数组
[0, n-1]
是候选区间。 - 我们的目标是保留 k 个最接近
x
的元素,等价于删除n - k
个最不接近的元素。 - 每次比较
arr[l]
和arr[r]
:- 如果
arr[l]
更接近x
(或距离相等但值更小),说明arr[r]
更“不重要”,可以删掉 →r--
- 否则,删掉
arr[l]
→l++
- 如果
- 重复
n - k
次后,剩下的[l, r]
就是答案。 - 由于原数组是升序排列,所以
[l, r]
本身也是升序,无需排序!
总之这种逆向思维的题还是很巧妙的,能够大大简化原做法。
class Solution {
public:vector<int> findClosestElements(vector<int>& arr, int k, int x) {int n=arr.size();vector<int>res;int l=0,r=n-1,cnt=0;while(l<=r&&cnt<n-k){if(abs(arr[l]-x)<abs(arr[r]-x)||abs(arr[l]-x)==abs(arr[r]-x)&&arr[l]<arr[r]){// temp.push_back(arr[r]);r--;cnt++;}else{// temp.push_back(arr[l]);l++;cnt++;}}for(int i=l;i<=r;++i){res.push_back(arr[i]);}// sort(res.begin(),res.end());return res;}
};