719. Find K-th Smallest Pair Distance
文章目錄
- 1 題目理解
- 2 分析思路
- 2.1 桶排序
- 2.2 二分+動態規劃
- 2.3 用堆實現
- 3相似題目786
- 3.1 二分
- 3.2 堆
1 題目理解
輸入:一個int數組nums,一個數字k
輸出:返回所有數字對中,數字對距離第k小的距離。
規則:一個數組中兩兩配對計算差值得到距離。距離值從小到大排序,第k位置的元素就是返回值。
例如
Input:
nums = [1,3,1]
k = 1
Output: 0
所有的配對距離是:
(1,3) -> 2
(1,1) -> 0
(3,1) -> 2
所有距離中從小到大排序,第1個是0,所以返回0。
Note:
2 <= len(nums) <= 10000.
0 <= nums[i] < 1000000.
1 <= k <= len(nums) * (len(nums) - 1) / 2.
2 分析思路
內容來源于花花醬。
2.1 桶排序
最直接的想法是用兩個for循環計算每個匹配對的距離,然后對距離進行排序。返回第k個元素 。排序算法選擇桶排序,加快速度。int[] distance記錄距離出現的次數。distance[0]表示有幾個配對的距離為0。
class Solution {public int smallestDistancePair(int[] nums, int k) {Arrays.sort(nums);int n = nums.length;int max = nums[n-1];int[] distance = new int[max+1];for(int i=0;i<n;i++){for(int j=i+1;j<n;j++){distance[nums[j] - nums[i]]++;}}for(int i = 0;i<max;i++){k -= distance[i];if(k<=0){return i;}}return 0;} }時間復雜度O(n2max)O(n^2max)O(n2max)
2.2 二分+動態規劃
我們先對數組nums排序。
返回值最小值是0,最大值=nums最大值-nums最小值。
用二分法查找返回值,也就是距離。
例如m=3,我們需要查找有多少個配對的距離小于等于3。
查找的方法使用動態規劃。
設dp[0] 為所有和nums[0]配對的距離小于等于3,有多少個。
dp[1]為所有和nums[0],nums[1]的配對距離小于等于3,有多少個。
…
dp[n-1]表示所有配對中距離小于等于3,有多少個。
例如nums={1,1,3,5,8}。
最開始,i=0,j=0,
nums[0] - nums[0] =0<=m,成立,j++;
nums[1]-nums[0]=1-1=0<=m,成立,j++;
nums[2]-nums[0]=3-1=2<=m,成立,j++;
nums[3]-nums[0]=5-1=4<=m,不成立,退出循環,因為數組是有序的,再比較下去,距離只會越來越大。
那么dp[0] = j-i-1=3-0-1=2,表示所有和nums[0]配對中,有2個配對的距離<=m。
接著計算i=1,此時j不需要從0開始。
配對(0,2)在上一步已經計算了,配對(1,2)的距離一定<=m。
因為nums[2]-nums[0]<=m,在上一步已經計算過了,而nums[1]>nums[0],同樣的數減去一個更大的數,差只能更小。
所以j不需要從0開始。
j=3,nums[3]-nums[1]=5-1=4<=m,不成立,退出循環。
dp[1] = dp[0] + (j-i-1)=3,表示所有和nums[0]、nums[1]配對中,有3個配對的距離<=m。
接著計算i=4,j=3。
…
時間復雜度O(nlogn)O(nlogn)O(nlogn),n應該是數組長度和數組最大值之間的最大值。當然最后的代碼還可以做空間優化。
2.3 用堆實現
參考力扣
首先將數組排序,排序之后,相鄰元素的差最小。先將nums[i]和nums[i+1],放入堆中,之后再依次將nums[i]和nums[i+2] nums[i]和nums[i+3]放入堆中 …
時間復雜度O((k+N)lgN),時間復雜度過高。
3相似題目786
3.1 二分
雖說相似,沒有找到規律還是理解不了的。即使找到規律了也不一定會數數,在O(n)時間復雜度內。
class Solution {public int[] kthSmallestPrimeFraction(int[] A, int K) {double l = 0;double r = 1.0;int[] answer = new int[2];while(l<r){double m = (l+r)/2;int[] res = countSmallerOrEqual(A,m);if(res[0] == K){answer[0] = res[1];answer[1] = res[2];break;}else if(res[0]>=K){r = m;}else{l = m;}}return answer;}private int[] countSmallerOrEqual(int[] A,double m){int count = 0;int p = 0,q = 1;int i=0;for(int j=1;j<A.length;j++){while(A[i]<=m*A[j]) i++;count += i;if(i>0){i=i-1;if(p*A[j]<q*A[i]){p = A[i];q = A[j];}}}return new int[]{count, p, q};}}對于countSmallerOrEqual函數不知道怎么寫,可以先用兩個for循環來寫。會發現i的循環可以提取出來。因為A數組是遞增的。例如[1,2,3,5]。如果1/2滿足條件,那么1/3一定滿足條件。因為分子不變,分母增加,數值會越來越小。
private int[] countSmallerOrEquals(int[] A ,double m){int count = 0;int p = 0,q = 1;for(int j=1;j<A.length;j++){int i=0;for(;i<j;i++){if(A[i]>m*A[j]){break;}}count += i;i=i-1;if(p*A[j]<q*A[i]){p = A[i];q = A[j];}}return new int[]{count, p, q};}3.2 堆
class Solution {public int[] kthSmallestPrimeFraction(int[] A, int k) {int[] answer = new int[2];PriorityQueue<int[]> pq = new PriorityQueue<int[]>((a, b) ->A[a[0]] * A[b[1]] - A[a[1]] * A[b[0]]);for(int i=1;i<A.length;i++){pq.offer(new int[]{0,i});}while(k>1){int[] vals = pq.poll();if(vals[0]+1 < vals[1]){pq.offer(new int[]{vals[0]+1,vals[1]});}k--;}answer = pq.poll();return new int[]{A[answer[0]],A[answer[1]]};}}總結
以上是生活随笔為你收集整理的719. Find K-th Smallest Pair Distance的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IOS 文件读取4种方法 转字符串 和d
- 下一篇: java。接口和抽象类区别