二分搜尋應用: 找第k小的配對距離_Find K-th Smallest Pair Dist_Leetcode #719

閱讀時間約 5 分鐘

題目敘述 719. Find K-th Smallest Pair Distance


給定一個輸入陣列nums和 參數k。

請找出第k小的pair distance是多少?


pair distance定義為 abs( nums[i] - nums[j]), i 不等於j

也就是任意兩陣列元素之間的差值絕對值


測試範例

Example 1:

Input: nums = [1,3,1], k = 1
Output: 0
Explanation: Here are all the pairs:
(1,3) -> 2
(1,1) -> 0
(3,1) -> 2
Then the 1st smallest distance pair is (1,1), and its distance is 0.

第一小的pair distance 是 0

Example 2:

Input: nums = [1,1,1], k = 2
Output: 0

第一小的pair distance 是 0
第二小的pair distance 是 0

Example 3:

Input: nums = [1,6,1], k = 3
Output: 5

第一小的pair distance 是 0
第二小的pair distance 是 5
第三小的pair distance 是 5

約束條件

Constraints:

  • n == nums.length

n = 陣列長度。

  • 2 <= n <= 10^4

陣列長度n介於2~一萬之間。

  • 0 <= nums[i] <= 10^6

每個陣列元素都介於0~一百萬之間。

  • 1 <= k <= n * (n - 1) / 2

參數k介於1 ~ C(n,2) 之間


觀察

除了暴力法計算全部pair dist再排序之外,其實還有更好的方法。


假如nums排序之後,那就變成從小到大依序放好的序列

這時候可以用最小pair dist和最大pair dist作為上下區間

往中間夾擠,看到哪一回合的時候,當下的pair dist剛好是第k小的。


演算法 排序前處理 + 二分搜尋法


承接觀察點的思考,先做前處理,將nums排序

這樣就滿足binary search的前提,接著用最小pair dist和最大pair dist作為上下區間

不斷砍半往中間夾擠pair dist,看到哪一回合的時候,當下的pair dist剛好是第k小的



程式碼 排序前處理 + 二分搜尋法

class Solution(object):
def countPairs(self, array, dist):
count = 0

# 累積看當下的 pair dist是第幾小的pair dist
for i in range(len(array)):
count += bisect.bisect_right(array, array[i] + dist, lo = i) - i - 1
return count

def smallestDistancePair(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
nums.sort()
low, high = min([abs(nums[i] - nums[i+1]) for i in range(len(nums) - 1)]), abs(nums[0] - nums[-1])

while low < high:
mid = (low + high)//2


if self.countPairs(nums, mid) < k:
# 假如不是第k小,而且還太小,則下一輪 pair dist猜大一點
low = mid + 1
elif self.countPairs(nums, mid) >= k:
# 假如不是第k小,而且還太大,則下一輪 pair dist猜小一點
# 假如mid是第k小,則下一輪 pair dist猜小一點,確認沒有更小的值也滿足
high = mid

return low


複雜度分析

時間複雜度: O( n log n)

前處理排序耗時O( n log n )

後續while loop + countPairs 總耗時也是O( n log n)


時間複雜度: O( n )

臨時變數用到長度為O(n)的list,所需空間為O(n)


關鍵知識點


遇到已排序的序列做搜尋,聯想到二分搜尋法。

如果輸入是亂序的,可以先做前處理排序,滿足二分搜尋法的前提。


強烈建議讀者一起復習相關的二分搜尋法框架和範例,鞏固知識點!

合縱連橫: 二分搜尋法框架_理解背後的本質


Reference

[1] 719. Find K-th Smallest Pair Distance

avatar-img
90會員
425內容數
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
給定一個輸入非負整樹陣列nums,請找出k值,使得陣列中恰好有k個元素大於等於 k。如果無解,回傳-1。尋找k值的方法包括排序法和二分搜尋法,時間複雜度都為O(n log n),空間複雜度為O(1)。關鍵知識點是當解空間具有遞增或遞減的性質時,可以用二分搜尋法加快搜尋效率。
這篇文章,會帶著大家複習以前學過的二分搜尋法(Binary Search)框架, 並且以二分搜尋法的概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個實用的演算法框架。 Binary search 二分搜尋法框架 用途: 在已經排序好的數列中尋找目標值。
找出區間[1, n] 內的軸心點位置。通過介紹直覺法、改良直覺法和二分搜尋等算法,最終給出了解析解(推導軸心點的公式解),提供了對應的程式碼和參考資料。該問題的最優解是使用解析解,能夠在O(1)的時間複雜度內找到答案。
題目會給我們一個山形的輸入陣列,和目標值target,要求我們找出目標值所在的陣列索引。如果出現兩次,返回比較小的那一個,也就是比較靠左的那個索引值。 山形的意思就是說,從最左側到山頂最大值都是遞增,從山頂最大值到右側都是遞減。
題目給定一個已排序的輸入陣列,陣列裡面的數字自分別代表每篇論文的被引用數。 要求我們計算h-index。 h-index的定義: 找一個最大的h值,使得有h篇論文,個別論文的被引用數都 大於等於 h
題目會給定一個2D 二維的矩陣,矩陣內的元素值代表對應的高度,要求我們找出相對最高點,也就是(大樓)高度大於N4 東、南、西、北 四個鄰居的索引值。 題目保證矩陣內相鄰的元素值都不相同,也又是相鄰的兩兩相比較,一定有一個比較高,有一個比較矮。
給定一個輸入非負整樹陣列nums,請找出k值,使得陣列中恰好有k個元素大於等於 k。如果無解,回傳-1。尋找k值的方法包括排序法和二分搜尋法,時間複雜度都為O(n log n),空間複雜度為O(1)。關鍵知識點是當解空間具有遞增或遞減的性質時,可以用二分搜尋法加快搜尋效率。
這篇文章,會帶著大家複習以前學過的二分搜尋法(Binary Search)框架, 並且以二分搜尋法的概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個實用的演算法框架。 Binary search 二分搜尋法框架 用途: 在已經排序好的數列中尋找目標值。
找出區間[1, n] 內的軸心點位置。通過介紹直覺法、改良直覺法和二分搜尋等算法,最終給出了解析解(推導軸心點的公式解),提供了對應的程式碼和參考資料。該問題的最優解是使用解析解,能夠在O(1)的時間複雜度內找到答案。
題目會給我們一個山形的輸入陣列,和目標值target,要求我們找出目標值所在的陣列索引。如果出現兩次,返回比較小的那一個,也就是比較靠左的那個索引值。 山形的意思就是說,從最左側到山頂最大值都是遞增,從山頂最大值到右側都是遞減。
題目給定一個已排序的輸入陣列,陣列裡面的數字自分別代表每篇論文的被引用數。 要求我們計算h-index。 h-index的定義: 找一個最大的h值,使得有h篇論文,個別論文的被引用數都 大於等於 h
題目會給定一個2D 二維的矩陣,矩陣內的元素值代表對應的高度,要求我們找出相對最高點,也就是(大樓)高度大於N4 東、南、西、北 四個鄰居的索引值。 題目保證矩陣內相鄰的元素值都不相同,也又是相鄰的兩兩相比較,一定有一個比較高,有一個比較矮。
你可能也想看
Google News 追蹤