問題描述:
給定一個整數數組,返回所有數對之間的第 k 個最小距離。一對 (A, B) 的距離被定義爲 A 和 B 之間的絕對差值。
示例 1:
輸入: nums = [1,3,1] k = 1 輸出:0 解釋: 所有數對如下: (1,3) -> 2 (1,1) -> 0 (3,1) -> 2 因此第 1 個最小距離的數對是 (1,1),它們之間的距離爲 0。
提示:
2 <= len(nums) <= 10000
.0 <= nums[i] < 1000000
.1 <= k <= len(nums) * (len(nums) - 1) / 2
.
基本思路:
利用二分法的本質來做。
我們一開始先確定整數數組距離的上下界,取中間,與計數結果比對,然後二分。
不過如果不預處理的話還是會tle。
預處理的意義就在於我們使用較小的複雜度來代替二分攜帶的較高複雜度。
比如,不預處理,我們的二分複雜度可能是O(mlogn); 預處理,我們的複雜度則可以是O(m + logn) = O(logn);
由此可以看出預處理的重要性。
而且這道題用到的預處理思路十分簡便且巧妙:
- 簡便就簡便在它只是在開頭時使用了一次排序。
- 巧妙則在於二分時的統計,本來需要一次二重循環,但是它通過讓內層循環不置零降低了複雜度。
具體地看代碼把:
AC代碼:
class Solution {
public:
int CountK(vector<int> &a, int k) {
int count = 0;
int left = 0;
for (int i = 1; i < a.size(); ++i) {
while (a[i] - a[left] > k) ++left;
count += (i - left);
}
return count;
}
int smallestDistancePair(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());
int left = 0;
int right = nums[nums.size() - 1] - nums[0];
while (left < right) {
int mid = left + (right - left) / 2;
int count = CountK(nums, mid); // 尋找比mid還要小的差值數
if (count >= k) right = mid;
else left = mid + 1;
}
return left;
}
};