トピック
ソートされた配列 arr、2 つの整数 k および x が与えられた場合、配列から x に最も近い k 個の数値 (2 つの数値間の最小差) を見つけます。返された結果は昇順で並べ替える必要があります。
整数 a は、整数 b が満たす必要があるよりも x に近いです:
|a - x| < |b - x| または
|a - x| == |b - x| および a < b
例 1:
入力: arr = [1,2,3,4,5]、k = 4、x = 3
出力: [1,2,3,4]
例 2:
入力: arr = [1,2,3,4,5]、k = 4、x = -1
出力: [1,2,3,4]
ヒント:
1 <= k <= arr.length
1 <= arr.length <= 104
arr 按 升序列
-104 <= arr[i], x <= 104
答え
x の絶対値を減算してシーケンスをソートし
、最初の k を取得します。
class Solution {
public:
vector<int> findClosestElements(vector<int>& arr, int k, int x) {
if(arr.size() == k)
return arr;
sort(arr.begin(),arr.end(),[=](int &a,int &b){
return abs(a-x)==abs(b-x)?a<b:abs(a-x)<abs(b-x);});
vector<int> res(arr.begin(), arr.begin() + k);
sort(res.begin(),res.end());
return res;
}
};
ダブルポインターは
両端から中央に向かってズームアウトします
class Solution {
public:
vector<int> findClosestElements(vector<int>& arr, int k, int x) {
int len = arr.size();
int left = 0;
int right = len-1;
while(right-left >= k)
{
int mid = left + (right-left)>1;
//cout<<abs(arr[left]-x) << " "<<abs(arr[right]-x)<<endl;
if( abs(arr[left]-x) > abs(arr[right]-x) )
left+=1;
else
right-=1;
}
//cout<<left<<" "<<right;
return vector(arr.begin()+left,arr.begin()+right+1);
}
};
二分探索 + ダブル ポインタ:
最初に x または左側に等しい添え字を見つけ
、次に左側に k ビット、右側に k ビットを拡散してから
、それを k ビットに圧縮します。
class Solution {
public:
vector<int> findClosestElements(vector<int>& arr, int k, int x) {
int len = arr.size();
int left = 0;
int right = len-1;
while(left<right)
{
int mid = ((right-left+1) >> 1) + left;
cout<<left<<"=="<<mid<<"=="<<right<<endl;
if(arr[mid]>x)
right = mid-1;
else
left = mid;
}
right = min(len-1,left+k);
left = max(0,left-k);
while(right-left+1 > k)
{
if( abs(arr[left]-x) > abs(arr[right]-x) )
left+=1;
else
right-=1;
}
return vector(arr.begin()+left,arr.begin()+right+1);
}
};