658. Find K Closest Elements
Given a sorted array, two integers k and x, find the k closest elements to x in the array. The result should also be sorted in ascending order. If there is a tie, the smaller elements are always preferred.
Example1
Input: [1,2,3,4,5], k=4, x=3
Output: [1,2,3,4]
Example2
Input: [1,2,3,4,5], k=4, x=-1
Output: [1,2,3,4]
Note:
The value k is positive and will always be smaller than the length of the sorted array.
Length of the given array is positive and will not exceed 104**
Absolute value of elements in the array and x will not exceed 104
分析:
首先找到x在有序队列中的位置(使用折半查找),然后再左右移动分别找到k个距离x最近的元素,找到k个元素后,再使用快排对其进行排序。为了节省特殊情况时的计算时间,也可以先判断特殊情况,判断x是否小于有序队列的最小值,或者大于有序队列的最大值,如果是特殊情况,那么就可以直接先前或向后的k个元素即可。一下介绍两种方法。
代码如下:
class Solution {
public:
//快速排序算法,一次循环
int QuikeSortOnce(int* &arr,int m,int n){
int low = m,high = n;
int povity = arr[low];
//cout<<low<<","<<high<<endl;
while(low<high){
while(low<high){
if(arr[high]>=povity)high--;/**一定要加等于号,负责会进入死循环**/
else{
//cout<<"high:"<<high<<endl;
arr[low] = arr[high];
arr[high]=povity;
break;
}
}
while(low<high){
if(arr[low]<=povity)low++;
else{
arr[high] = arr[low];
arr[low] = povity;
break;
}
}
}
return low;
}
//快速排序,递归调用
void QuikeSort(int *&arr,int low,int high){
if(low<high){
int mid = QuikeSortOnce(arr,low,high);
QuikeSort(arr,low,mid-1);
QuikeSort(arr,mid+1,high);
}
}
//折半查找
int search_bin(vector<int> arr,int key){
int low = 0,high = arr.size()-1;
while(low<=high){
int mid = (low+high)/2;
if(arr[mid]<key)low = mid+1;
else if(arr[mid]>key)high = mid-1;
else return mid;
}
return high;
}
vector<int> findClosestElements(vector<int>& arr, int k, int x) {
int len = arr.size();
vector<int> q;
if(x>=arr[len-1]){
int c = 1;
while(c<=k){
q.push_back(arr[len-1]);
c++;
len--;
}
reverse(q.begin(),q.end());
return q;
}else if(x<=arr[0]){
int c = 1;
while(c<=k){
q.push_back(arr[c-1]);
c++;
}
return q;
}else{
int *res;
res = (int *)malloc(sizeof(int)*k);
int l = search_bin(arr,x);
int c=1;
int low = l,high = l+1;
while(c<=k){
if(low>=0&&high<=len-1&&abs(x-arr[low])<=abs(x-arr[high])){
res[c-1] = arr[low];
low = low-1;
}else if(low>=0&&high<=len-1&&abs(x-arr[low])>abs(x-arr[high])) {
res[c-1] = arr[high];
high = high+1;
}else if(low<0){
res[c-1] = arr[high];
high = high +1;
}else if(high>len-1){
res[c-1] = arr[low];
low = low-1;
}
c++;
}
QuikeSort(res,0,k-1);
for(int i=0;i<k;i++)q.push_back(res[i]);
return q;
}
}
};
法二:(代码精简版java)
public List<Integer> findClosestElements(List<Integer> arr, int k, int x) {
List<Integer> ans = new ArrayList<>();
if (arr.size() == 0) return ans;
Collections.sort(arr, new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
int ax = Math.abs(a - x);
int bx = Math.abs(b - x);
if (ax != bx) return ax - bx;
return a - b;
}
});
ans = new ArrayList<Integer>(arr.subList(0, Math.min(k, arr.size())));
Collections.sort(ans);
return ans;
}