一道騰訊筆試題,附我的詳細答案

做算法題,可能與我們平時編寫業務邏輯的思維方式可能還不太一樣。作算法題需要理解其中的原理,構思分析問題的方法,勤於總結,只有這樣才能逐漸養成算法思維,而不是隻有純寫業務邏輯的思維。

今天透過一道騰訊的筆試題:合併區間,體會算法思維對程序員的重要性。

合併區間

給出一個區間的集合,請合併所有重疊的區間。

示例 1:

輸入: [[1,3],[2,6],[8,10],[15,18]]

輸出: [[1,6],[8,10],[15,18]]

解釋: 區間 [1,3] 和 [2,6] 重疊, 將它們合併爲 [1,6].

示例 2:

輸入: [[1,4],[4,5]]

輸出: [[1,5]]

解釋: 區間 [1,4] 和 [4,5] 可被視爲重疊區間。

補全下面代碼:

class Solution(object):
    def merge(self, intervals):

說明,這道題看似簡單,實際需要考慮周全。比如出現這樣的區間:

  1. 輸入爲 []

  2. [[1,4],[2,4]]

  3. 邊界情況 [[1,3],[3,4]]

  4. 複雜情況 [[1,2],[3,4],[5,6],[0,10],[7,12]]

同時要求時間複雜度儘可能低。

2 分析

S1:首先考慮構成本題的基本結構:如何判斷兩個線段是否有交集:

兩個線段有交集的四種情況:

統一滿足以上不等式條件:

兩個線段無交集的情況:

統一滿足以上不等式條件:

S2:合併一堆線段

如下一堆線段,圖中標號爲線段的編號:

爲了使得操作更加有序,第一感覺按照線段的左端點從小到大排序:

這樣確保第個線段左端點不大於第個線段左端點。

S3:設置數組 dp

設數組dp[i] 表示合併第i 條線段後的解,即此時數組dp內的各條線段都已經不能再合併。

下面就變爲:

已知dp[i],如何合併第i+1條線段,進而推導出 dp[i+1]

若數組dp中最後一個元素的左端點不小於第i+1條線段的右端點,則可與之合併,即滿足:

否則無法合併,直接加入到dp中。

轉化爲代碼:

 if item[0] <= dp[-1][1]:  
    dp[-1][1] = max(dp[-1][1],item[1]) # 合併第i+1段
 else:
    dp.append(item) # 無法合併,直接加入到dp中

dp數組的初始值爲排序後的第一條線段。

S4:轉化代碼


class Solution(object):
    def merge(self, intervals):
        if len(intervals)==0: return intervals
        a = sorted(intervals,key=lambda x: (x[0],x[1]))
        dp = [a[0]]
        for item in a[1:]:
            if item[0] <= dp[-1][1]:  
                dp[-1][1] = max(dp[-1][1],item[1])
            else:
                dp.append(item)
        return dp

一般排序時間複雜度爲 O(nlogn),後面 for 循環時間複雜度爲 O(n),所以綜合時間複雜度爲 O(nlogn)。

本題目先試用排序降低一部分分析難度,後面使用動態規劃思想,問題變化爲:已知 dp[i] 如何求出 dp[i+1]問題,並且經過排序後是否合併只與dp[-1]有關。

歡迎加入星球,從零學程序員必備算法,每天在星球內記錄學習過程、學習星友超讚的回答,還會不定期送精華資料!打卡 300 天,退還除平臺收取的其他所有費用。

長按二維碼,查看我的星球

Day1-Day35 已刷題目總結:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章