區間交集問題


本文是區間系列問題的第三篇,前兩篇分別講了區間的最大不相交子集和重疊區間的合並,今天再寫一個算法,可以快速找出兩組區間的交集。

先看下題目,LeetCode 第 986 題就是這個問題:

title

題目很好理解,就是讓你找交集,注意區間都是閉區間。

思路

解決區間問題的思路一般是先排序,以便操作,不過題目說已經排好序了,那么可以用兩個索引指針在 AB 中游走,把交集找出來,代碼大概是這樣的:

# A, B 形如 [[0,2],[5,10]...]
def intervalIntersection(A, B):
    i, j = 0, 0
    res = []
    while i < len(A) and j < len(B):
        # ...
        j += 1
        i += 1
    return res

不難,我們先老老實實分析一下各種情況。

首先,對於兩個區間,我們用 [a1,a2][b1,b2] 表示在 AB 中的兩個區間,那么什么情況下這兩個區間沒有交集呢:

只有這兩種情況,寫成代碼的條件判斷就是這樣:

if b2 < a1 or a2 < b1:
    [a1,a2] 和 [b1,b2] 無交集

那么,什么情況下,兩個區間存在交集呢?根據命題的否定,上面邏輯的否命題就是存在交集的條件:

# 不等號取反,or 也要變成 and
if b2 >= a1 and a2 >= b1:
    [a1,a2] 和 [b1,b2] 存在交集

接下來,兩個區間存在交集的情況有哪些呢?窮舉出來:

這很簡單吧,就這四種情況而已。那么接下來思考,這幾種情況下,交集是否有什么共同點呢?

我們驚奇地發現,交集區間是有規律的!如果交集區間是 [c1,c2],那么 c1=max(a1,b1)c2=min(a2,b2)!這一點就是尋找交集的核心,我們把代碼更進一步:

while i < len(A) and j < len(B):
    a1, a2 = A[i][0], A[i][1]
    b1, b2 = B[j][0], B[j][1]
    if b2 >= a1 and a2 >= b1:
        res.append([max(a1, b1), min(a2, b2)])
    # ...

最后一步,我們的指針 ij 肯定要前進(遞增)的,什么時候應該前進呢?

結合動畫示例就很好理解了,是否前進,只取決於 a2b2 的大小關系:

while i < len(A) and j < len(B):
    # ...
    if b2 < a2:
        j += 1
    else:
        i += 1

代碼

# A, B 形如 [[0,2],[5,10]...]
def intervalIntersection(A, B):
    i, j = 0, 0 # 雙指針
    res = []
    while i < len(A) and j < len(B):
        a1, a2 = A[i][0], A[i][1]
        b1, b2 = B[j][0], B[j][1]
        # 兩個區間存在交集
        if b2 >= a1 and a2 >= b1:
            # 計算出交集,加入 res
            res.append([max(a1, b1), min(a2, b2)])
        # 指針前進
        if b2 < a2: j += 1
        else:       i += 1
    return res

總結一下,區間類問題看起來都比較復雜,情況很多難以處理,但實際上通過觀察各種不同情況之間的共性可以發現規律,用簡潔的代碼就能處理。

另外,區間問題沒啥特別厲害的奇技淫巧,其操作也朴實無華,但其應用卻十分廣泛,接之前的幾篇文章:

我最近精心制作了一份電子書《labuladong的算法小抄》,分為【動態規划】【數據結構】【算法思維】【高頻面試】四個章節,共 60 多篇原創文章,絕對精品!限時開放下載,在我的公眾號 labuladong 后台回復關鍵詞【pdf】即可免費下載!

目錄

歡迎關注我的公眾號 labuladong,技術公眾號的清流,堅持原創,致力於把問題講清楚!

labuladong


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM