leetcode數組中的問題(二)

 

 

目錄

15. 三數之和

18. 四數之和

454. 四數相加 II

280. 擺動排序🔒

324. 擺動排序 II

347. 前 K 個高頻元素

977. 有序數組的平方

360. 有序轉化數組🔒

986. 區間列表的交集

56. 合併區間


15. 三數之和

https://leetcode-cn.com/problems/3sum/submissions/

給定一個包含 n 個整數的數組 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?找出所有滿足條件且不重複的三元組。注意:答案中不可以包含重複的三元組。

示例:給定數組 nums = [-1, 0, 1, 2, -1, -4],滿足要求的三元組集合爲:[[-1, 0, 1],[-1, -1, 2]]

思路

該題主要的難點是如何去重

一:先將數組排序,然後二重循環+哈希表尋找可行解,並藉助set的特性進行去重。也在過程中進行了類似剪枝操作,但是沒去除乾淨。

class Solution(object):
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        if len(nums) < 3:
            return []
        
        res = []
        nums = sorted(nums)
        rec = set([nums[0]])
        unique_rec = set()
        
        for i in range(1, len(nums)):
            if i >= 3 and nums[i] == nums[i - 2]:
                continue
            for j in range(i + 1, len(nums)):
                if j >= i + 2 and nums[j] == nums[j - 1]:
                    continue
                t = 0 - nums[i] - nums[j]
                if t in rec and (t, nums[i], nums[j]) not in unique_rec:
                    res.append([t, nums[i], nums[j]])
                    unique_rec.add((t, nums[i], nums[j]))
            rec.add(nums[i])
        return res

二:藉助兩數之和的思路,用雙指針。先排序,此處排序是方便在過程中就可以剔除重複解,固定一個數,用雙指針尋找可行解。

令左指針 l=i+1,右指針 r=n−1,當 l<r 時,執行循環:當 nums[i]+nums[l]+nums[r]==0,執行循環,判斷左界和右界是否和下一位置重複,去除重複解。並同時將 l,r 移到下一位置,尋找新的解。

while l < r and nums[l] == nums[l + 1]:
    l += 1
while l < r and nums[r] == nums[r - 1]:
    r -= 1
l += 1
r += 1
class Solution(object):
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        if len(nums) < 3:
            return []
        nums = sorted(nums)
        res = []

        for i in range(len(nums)):
            if i > 0 and nums[i] == nums[i - 1]:
                continue

            l, r = i + 1, len(nums) - 1
            while l < r:
                if nums[i] + nums[l] + nums[r] < 0:
                    l += 1
                elif nums[i] + nums[l] + nums[r] > 0:
                    r -= 1
                else:
                    res.append([nums[i], nums[l], nums[r]])
                    lv, rv = nums[l], nums[r]
                    l += 1
                    r -= 1
                    while l < r and nums[l] == lv:
                        l += 1
                    while l < r and nums[r] == rv:
                        r -= 1
        return res

 

18. 四數之和

https://leetcode-cn.com/problems/4sum/

給定一個包含 n 個整數的數組 nums 和一個目標值 target,判斷 nums 中是否存在四個元素 a,b,c 和 d ,使得 a + b + c + d 的值與 target 相等?找出所有滿足條件且不重複的四元組。注意:答案中不可以包含重複的四元組。

示例:給定數組 nums = [1, 0, -1, 0, -2, 2],和 target = 0。滿足要求的四元組集合爲:[[-1,  0, 0, 1],[-2, -1, 1, 2], [-2,  0, 0, 2]]。

思路

一:藉助兩數之和的思路,用雙指針。先排序,此處排序是方便在過程中就可以剔除重複解,固定兩個數,用雙指針尋找可行解,時間複雜度O(n^3)。

class Solution(object):
    def fourSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        if len(nums) < 4:
            return []
        nums = sorted(nums)
        res = []

        for i in range(len(nums)):
            if i >= 1 and nums[i] == nums[i - 1]:
                continue
            for j in range(i + 1, len(nums)):
                if j > i + 1 and nums[j] == nums[j - 1]:
                    continue
                l, r = j + 1, len(nums)  - 1
                while l < r:
                    if nums[l] + nums[r] + nums[i] + nums[j] > target:
                        r -= 1
                    elif nums[l] + nums[r] + nums[i] + nums[j] < target:
                        l += 1
                    else:
                        res.append([nums[i], nums[j], nums[l], nums[r]])
                        lv, rv = nums[l], nums[r]
                        l += 1
                        r -= 1
                        while l < r and nums[l] == lv:
                            l += 1
                        while l < r and nums[r] == rv:
                            r -= 1
        return res

454. 四數相加 II

https://leetcode-cn.com/problems/4sum-ii/

給定四個包含整數的數組列表 A , B , C , D ,計算有多少個元組 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。爲了使問題簡單化,所有的 A, B, C, D 具有相同的長度 N,且 0 ≤ N ≤ 500 。所有整數的範圍在 -228 到 228 - 1 之間,最終結果不會超過 231 - 1 。

例如:輸入:A = [ 1, 2],B = [-2,-1],C = [-1, 2],D = [ 0, 2],輸出:2,解釋:兩個元組如下:1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0,2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0。

思路

一:先兩重循環遍歷A、B,將和記錄到字典rec中(鍵:和,值:和爲該值的二元組的數目),兩重循環遍歷C、D,若字典中存在元素(component)能和他們的和爲0,則又有rec[component]個數的元組。

from collections import defaultdict
class Solution(object):
    def fourSumCount(self, A, B, C, D):
        """
        :type A: List[int]
        :type B: List[int]
        :type C: List[int]
        :type D: List[int]
        :rtype: int
        """
        n = len(A)
        if n == 0:
            return 0
        
        rec = defaultdict(int)

        for i in range(n):
            for j in range(n):
                rec[A[i] + B[j]] += 1
        res = 0
        for i in range(n):
            for j in range(n):
                component = 0 - C[i] - D[j]
                if component in rec:
                    res += rec[component]
        return res

280. 擺動排序

https://leetcode-cn.com/problems/wiggle-sort/submissions/

給你一個無序的數組 nums, 將該數字 原地 重排後使得 nums[0] <= nums[1] >= nums[2] <= nums[3]...。

示例:輸入: nums = [3,5,2,1,6,4],輸出: 一個可能的解答是 [3,5,1,6,2,4]

思路

一:將原數組非原址排序得到一個新的由小至大排好序的數組new_nums,把new_nums中的元素依次填入到nums的偶數位,再依次填入到奇數位即滿足要求,時間複雜度O(nlgn),排序要O(nlgn)的時間複雜度,空間複雜度O(n)。例如nums = [3,5,2,1,6,4],則new_nums=[1, 2, 3, 4, 5, 6],第一輪填入後會改變nums偶數位的值,nums = [1,5,2,1,3,4],第二輪填入後會改變nums奇數位的值,nums=[1,4,2,5,3,6]。

class Solution(object):
    def wiggleSort(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        new_nums = sorted(nums)

        cur = 0
        for i in range(0, len(nums), 2):
            nums[i] = new_nums[cur]
            cur += 1
        for i in range(1, len(nums), 2):
            nums[i] = new_nums[cur]
            cur += 1

二:還是需要將原數組排序,不過可以原址排序,從第二個元素開始每兩個元素交換一下位置,時間複雜度O(nlgn),排序要O(nlgn)的時間複雜度,空間複雜度O(1)。

  [1, 2, 3, 4, 5, 6]
      ↑  ↑  ↑  ↑
      swap  swap

=> [1, 3, 2, 5, 4, 6]
class Solution(object):
    def wiggleSort(self, nums):
        nums.sort()
        for i in range(1, len(nums) - 1 , 2):
            nums[i], nums[i + 1] = nums[i + 1], nums[i]

三:轉一個leetcode的官方解答,可以只用一遍完成任務。當我們遍歷整個數組,比較當前元素與下一個元素。若順序不正確,則交換之。https://leetcode-cn.com/problems/wiggle-sort/solution/bai-dong-pai-xu-by-leetcode/

class Solution(object):
    def wiggleSort(self, nums):
        less = True
        for i in range(len(nums) - 1):
            if less:
                if nums[i] > nums[i + 1]:
                    nums[i], nums[i + 1] = nums[i + 1], nums[i]
            else:
                if nums[i] < nums[i + 1]:
                    nums[i], nums[i + 1] = nums[i + 1], nums[i]
            less = not less

324. 擺動排序 II

https://leetcode-cn.com/problems/wiggle-sort-ii/

給定一個無序的數組 nums,將它重新排列成 nums[0] < nums[1] > nums[2] < nums[3]... 的順序。

示例 1:輸入: nums = [1, 5, 1, 1, 6, 4],輸出: 一個可能的答案是 [1, 4, 1, 5, 1, 6]
示例 2:輸入: nums = [1, 3, 2, 2, 3, 1],輸出: 一個可能的答案是 [2, 3, 1, 3, 1, 2]
說明:你可以假設所有輸入都會得到有效的結果。進階:你能用 O(n) 時間複雜度和 / 或原地 O(1) 額外空間來實現嗎?

思路

乍一看,與280擺動排序幾乎一樣,但是此題更加嚴格,必須嚴格大於或小於,不能等於,280的三種解法全不適用。該題的思路是轉自leetcode上看到的題解https://leetcode-cn.com/problems/wiggle-sort-ii/solution/yi-bu-yi-bu-jiang-shi-jian-fu-za-du-cong-onlognjia/,怕以後找不到,自己copy了一段。

一:首先,我們可以很容易想到一種簡單的解法:將數組進行排序,然後從中間位置進行等分(如果數組長度爲奇數,則將中間的元素分到前面),然後將兩個數組進行穿插。例如:對於數組[1, 5, 2, 4, 3],我們將其排序,得到[1, 2, 3, 4, 5],然後將其分割爲[1, 2, 3]和[4, 5],對兩個數組進行穿插,得到[1, 4, 2, 5, 3]。

但是這一解法有一個問題,例如,對於數組[1, 2, 2, 3],按照這種做法求得的結果仍爲[1, 2, 2, 3]。如果題目不要求各元素嚴格大於或小於相鄰元素,即,只要求nums[0] <= nums[1] >= nums[2] <= nums[3]...,那麼這一解法是符合要求的,但題目要求元素相互嚴格大於或小於,那麼需要稍微做一點改進。

爲了方便閱讀,我們在下文中定義較小的子數組爲數組A,較大的子數組爲數組B。顯然,出現上述現象是因爲nums中存在重複元素實際上,由於穿插之後,相鄰元素必來自不同子數組,所以A或B內部出現重複元素是不會出現上述現象的。所以,出現上述情況其實是因爲數組A和數組B出現了相同元素,我們用r來表示這一元素。而且我們可以很容易發現,如果A和B都存在r,那麼r一定是A的最大值,B的最小值,這意味着r一定出現在A的尾部,B的頭部。其實,如果這一數字的個數較少,不會出現這一現象,只有當這一數字個數達到原數組元素總數的一半,纔會在穿插後的出現在相鄰位置。以下舉幾個例子進行形象地說明:例如,對於數組[1,1,2,2,3,3],分割爲[1,1,2]和[2,3,3],雖然A和B都出現了2,但穿插後爲[1,2,1,3,2,3],滿足要求。
而如果2的個數再多一些,即[1,1,2,2,2,3],分割爲[1,1,2]和[2,2,3],最終結果爲[1,2,1,2,2,3],來自A的2和來自B的2出現在了相鄰位置。出現這一問題是因爲重複數在A和B中的位置決定的,因爲r在A尾部,B頭部,所以如果r個數太多(大於等於(length(nums) + 1)/2),就可能在穿插後相鄰。要解決這一問題,我們需要使A的r和B的r在穿插後儘可能分開。一種可行的辦法是將A和B反序:例如,對於數組[1,1,2,2,2,3],分割爲[1,1,2]和[2,2,3],分別反序後得到[2, 1, 1]和[3, 2, 2],此時2在A頭部,B尾部,穿插後就不會發生相鄰了。當然,這隻能解決r的個數等於(length(nums) + 1)/2的情況,如果r的個數大於(length(nums) + 1)/2,還是會出現相鄰。但實際上,這種情況是不存在有效解的,也就是說,這種數組對於本題來說是非法的。此時我們得到了第一個解法,由於需要使用排序,所以時間複雜度爲O(NlogN),由於需要存儲A和B,所以空間複雜度爲O(N)。

class Solution(object):
    def wiggleSort(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        rec = sorted(nums)
        n = len(rec)
        # 將a、b反序,儘量避開重合元素
        a = rec[0: (n - 1) // 2 + 1][::-1]
        b = rec[(n - 1) // 2 + 1:][::-1]
        for i in range(len(a)):
            nums[i * 2] = a[i]
            if i < len(b):
                nums[i * 2 + 1] = b[i]

二:上一解法之所以時間複雜度爲O(NlogN),是因爲使用了排序。但回顧解法1,我們發現,我們實際上並不關心A和B內部的元素順序,只需要滿足A和B長度相同(或相差1),且A中的元素小於等於B中的元素,且r出現在A的頭部和B的尾部即可。實際上,由於A和B長度相同(或相差1),所以r實際上是原數組的中位數。因此,我們第一步其實不需要進行排序,而只需要找到中位數即可。而尋找中位數可以用快速選擇算法實現,時間複雜度爲O(n)。加之需要滿足A和B長度相同(或相差1)只能使用三路快排,保證中位數在中間且相鄰,便於切分。

from random import randint
class Solution(object):
    def wiggleSort(self, nums):
        if len(nums) <= 1:
            return
        mid = (len(nums) - 1) // 2
        self._quick_select(nums, 0, len(nums) - 1, mid)
        a = nums[0: mid + 1][::-1]
        b = nums[mid + 1:][::-1]
        for i in range(len(a)):
            nums[i * 2] = a[i]
            if i < len(b):
                nums[i * 2 + 1] = b[i]

    def _quick_select(self, nums, l, r, mid):
        if l >= r:
            return
        lt, gt = self._helper(nums, l, r)
        if lt >= mid:
            self._quick_select(nums, l, lt, mid)
        elif gt <= mid:
            self._quick_select(nums, gt, r, mid)

    # [l,r]
    def _helper(self, nums, l, r):
        # randint(a, b) : Return random integer in range [a, b], including both end points
        idx = randint(l, r)
        self._swap(nums, l, idx)
        val = nums[l]
        # [l+1, lt] < val, (lt, i) == val, [gt, r] > val
        lt, gt, i = l, r + 1, l + 1
        while i < gt:
            if nums[i] < val:
                self._swap(nums, lt + 1, i)
                i += 1
                lt += 1
            elif nums[i] == val:
                i += 1
            else:
                self._swap(nums, gt - 1, i)
                gt -= 1
        # [l+1, lt - 1] < val, [lt, i) == val
        self._swap(nums, lt, l)
        lt -= 1
        return lt, gt

    def _swap(self, nums, i, j):
        nums[i], nums[j] = nums[j], nums[i]

347. 前 K 個高頻元素

https://leetcode-cn.com/problems/top-k-frequent-elements/

給定一個非空的整數數組,返回其中出現頻率前 k 高的元素。

示例 1:輸入: nums = [1,1,1,2,2,3], k = 2,輸出: [1,2]
示例 2:輸入: nums = [1], k = 1,輸出: [1]

說明:你可以假設給定的 k 總是合理的,且 1 ≤ k ≤ 數組中不相同的元素的個數。你的算法的時間複雜度必須優於 O(n log n) , n 是數組的大小。

思路

一:藉助字典(鍵-元素值,值-元素頻率),將字典按值排序。取前k個,時間複雜度O(nlgn)。

from collections import defaultdict

class Solution(object):
    def topKFrequent(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        rec = defaultdict(int)
        for i in range(len(nums)):
            rec[nums[i]] += 1
        rec = sorted(rec.items(), key=lambda a: a[1], reverse=True)
        count, res = 0, []
        for item in rec:
            if count >= k:
                break
            res.append(item[0])
            count += 1
        return res

二:藉助堆,時間複雜度O(nlgk)。

class Solution(object):
    def topKFrequent(self, nums, k):
        rec = collections.Counter(nums)
        return heapq.nlargest(k, rec.keys(), rec.get)

977. 有序數組的平方

https://leetcode-cn.com/problems/squares-of-a-sorted-array/

給定一個按非遞減順序排序的整數數組 A,返回每個數字的平方組成的新數組,要求也按非遞減順序排序。

示例 1:輸入:[-4,-1,0,3,10],輸出:[0,1,9,16,100]
示例 2:輸入:[-7,-3,2,3,11],輸出:[4,9,9,49,121]
提示:1 <= A.length <= 10000,-10000 <= A[i] <= 10000,A 已按非遞減順序排序。

思路:

一:整體,絕對值排序後做平方,將A的小於0的元素乘以-1加入lt,大於等於零的加入gt,則lt由大到小排序,gt由小到大,將兩個有序數組排序只需要O(n)的時間複雜度,排好序後再做平方,O(n)的時間複雜度,空間複雜度也是O(n)。

class Solution(object):
    def sortedSquares(self, A):
        """
        :type A: List[int]
        :rtype: List[int]
        """
        lt, gt = [], []
        for item in A:
            if item < 0:
                lt.append(-1 * item)
            else:
                gt.append(item)
        l, g, i = len(lt) - 1, 0, 0
        a = [0] * len(A)
        while l >= 0 or g < len(gt):
            if l < 0:
                a[i] = gt[g]
                g += 1
            elif g >= len(gt):
                a[i] = lt[l]
                l -= 1
            elif lt[l] < gt[g]:
                a[i] = lt[l]
                l -= 1
            else:
                a[i] = gt[g]
                g += 1
            i += 1
        for i in range(len(a)):
            a[i] *= a[i]
        return a

360. 有序轉化數組

https://leetcode-cn.com/problems/sort-transformed-array/submissions/

給你一個已經 排好序 的整數數組 nums 和整數 a、b、c。對於數組中的每一個數 x,計算函數值 f(x) = ax2 + bx + c,請將函數值產生的數組返回。要注意,返回的這個數組必須按照 升序排列,並且我們所期望的解法時間複雜度爲 O(n)。

示例 1:輸入: nums = [-4,-2,2,4], a = 1, b = 3, c = 5,輸出: [3,9,15,33]
示例 2:輸入: nums = [-4,-2,2,4], a = -1, b = 3, c = 5,輸出: [-23,-5,1,7]

思路

 一:利用二次函數的特性,要麼是單調的(退化成一次函數或者常數,全在二次函數對稱軸的左側或右側),單調的在特判中處理了。剩下的就是非單調的,那麼必定存在一個分界線,分界線的一邊遞增,另一邊遞減,遞增的加入asc,遞減的加入desc,得到兩個有序數組,合併兩個有序數組即是解。注意:數組中可能有重複的元素。

class Solution(object):
    def sortTransformedArray(self, nums, a, b, c):
        """
        :type nums: List[int]
        :type a: int
        :type b: int
        :type c: int
        :rtype: List[int]
        """
        if not nums:
            return nums
        res = [a * item * item + b * item + c for item in nums]
        # 特判
        if len(res) == 1:
            return res
        if self._check_asc(res):
            return res
        res = res[::-1]
        if self._check_asc(res):
            return res

        if a < 0:
            # 先升後降
            d_idx = 1
            while d_idx < len(nums):
                if res[d_idx] < res[d_idx - 1]:
                    break
                d_idx += 1
            asc, desc = res[:d_idx], res[d_idx:]
        else:
            # 先降後升
            a_idx = 1
            while a_idx < len(nums):
                if res[a_idx] > res[a_idx - 1]:
                    break
                a_idx += 1
            asc, desc = res[a_idx:], res[:a_idx]
        # 這邊是將兩個有序數組合並
        i, a_idx, d_idx = 0, 0, len(desc) - 1
        while i < len(res):
            if a_idx >= len(asc):
                res[i] = desc[d_idx]
                d_idx -= 1
            elif d_idx < 0:
                res[i] = asc[a_idx]
                a_idx += 1
            elif asc[a_idx] < desc[d_idx]:
                res[i] = asc[a_idx]
                a_idx += 1
            else:
                res[i] = desc[d_idx]
                d_idx -= 1
            i += 1
        return res
    
    # 是遞增序
    def _check_asc(self, res):
        for i in range(1, len(res)):
            if res[i] < res[i - 1]:
                return False
        return True

986. 區間列表的交集

https://leetcode-cn.com/problems/interval-list-intersections/

給定兩個由一些閉區間組成的列表,每個區間列表都是成對不相交的,並且已經排序。返回這兩個區間列表的交集。(形式上,閉區間 [a, b](其中 a <= b)表示實數 x 的集合,而 a <= x <= b。兩個閉區間的交集是一組實數,要麼爲空集,要麼爲閉區間。例如,[1, 3] 和 [2, 4] 的交集爲 [2, 3]。)

示例:

輸入:A = [[0,2],[5,10],[13,23],[24,25]], B = [[1,5],[8,12],[15,24],[25,26]],輸出:[[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]],注意:輸入和所需的輸出都是區間對象組成的列表,而不是數組或列表。
提示:0 <= A.length < 1000,0 <= B.length < 1000,0 <= A[i].start, A[i].end, B[i].start, B[i].end < 10^9

思路

一:因爲區間列表已經排好序,此題中若固定B列表中的區間,將A列表的區間的起始點與B中該區間的起始點對比,將A與B的相對位置的所有情況寫出來,即是解。

class Solution(object):
    def intervalIntersection(self, A, B):
        """
        :type A: List[List[int]]
        :type B: List[List[int]]
        :rtype: List[List[int]]
        """
        res = []
        if not A or not B:
            return res

        i, j = 0, 0

        while i < len(A) and j < len(B):
            # A[i]終點在B[j]起點的左側,沒有交集
            if A[i][1] < B[j][0]:
                i += 1
            # A[i]起點在B[j]起點的左側,且A[i]終點在B[j]起點的右側,必有交集,討論終點
            elif A[i][0] < B[j][0]:
                end = min(A[i][1], B[j][1])
                res.append([B[j][0], end])
                # 討論終點,看看哪個區間被用完要往後挪
                if end == A[i][1]:
                    i += 1
                if end == B[j][1]:
                    j += 1
            # A[i]起點在B[j]起點的右側,且A[i]終點在B[j]起點的右側,討論是否有交集
            else:
                # A[i]起點在B[j]終點的右側,無交集
                if A[i][0] > B[j][1]:
                    j += 1
                # 討論終點,看看哪個區間被用完要往後挪
                else:
                    end = min(A[i][1], B[j][1])
                    res.append([A[i][0], end])
                    if end == A[i][1]:
                        i += 1
                    if end == B[j][1]:
                        j += 1
        return res

二:從示例圖以及方法一的代碼中我們可以看出,無論是否有交集,A或B中都必定至少有一個指向下一個區間,我們可以對比A和B的終點決定誰要指向下一個區間,當然若存在交集,將交集添入res。

class Solution(object):
    def intervalIntersection(self, A, B):
        # 特判
        if not A or not B:
            return []

        i, j, res = 0, 0, []
        while i < len(A) and j < len(B):
            low = max(A[i][0], B[j][0])
            high = min(A[i][1], B[j][1])
            # 存在交集
            if low <= high:
                res.append([low, high])
            if A[i][1] < B[j][1]:
                i += 1
            else:
                j += 1
        return res

56. 合併區間

https://leetcode-cn.com/problems/merge-intervals/submissions/

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

示例 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] 可被視爲重疊區間。

思路

一:按起點排序,由前向後遍歷,此時能否重合之需要比較終點是否大於等於待考察區間的起點,若是則可以合併,更新終點值;若不是,則不可以合併,將之前的區間加入res,並把該區間作爲第一個區間繼續考察下去。推出循環後要記住將最後一組low,high加入res。

通常遇到區間問題要對區間進行排序,常見的按起點排序或按終點排序,此處選擇按起點排序,因爲後面是由前向後遍歷的,若按終點排序,則[[2,3],[4,5],[6,7],[8,9],[1,10]]會得出[[2,3],[4,5],[6,7],[1,10]]的結果,實際上應該是[[1,10]],第一個區間和第二個區間不重合,但是所有區間均在在最後一個區間表示的範圍內,即若按終點排序,同時由前向後遍歷,我們無法確定第一個遍歷到的起點一定是真正的起點,但是按起點排序,由前向後遍歷,則可以確定第一個區間的起點一定是起點,可以解決上述情況,此時第一個區間要麼與別的可以合併但是起點是第一個區間的起點,若不能合併,起點顯然也是第一個區間的起點。(若按終點排序,則應該由後向前遍歷,比較起點與待考察區間終點的關係,此時也能保證由後向前的第一個區間的終點必定是終點)。

 在確定可以合併時,區間的終點在待考察區間起點的右側,取原先終點和待考察區間終點的最大值,若只取待考察區間的終點,則[[1,4],[2,3]]結果爲[[1,3]],其實應爲[[1,4]]

if high >= intervals_sort[i][0]:
    high = max(high, intervals_sort[i][1])
class Solution(object):
    def merge(self, intervals):
        """
        :type intervals: List[List[int]]
        :rtype: List[List[int]]
        """
        if len(intervals) <= 1:
            return intervals

        intervals_sort = sorted(intervals, key=lambda a:a[0])

        low, high, res = intervals_sort[0], []
        for i in range(1, len(intervals_sort)):
            if high >= intervals_sort[i][0]:
                high = max(high, intervals_sort[i][1])
            else:
                res.append([low, high])
                low, high = intervals_sort[i]
        res.append([low, high])
        return res

 

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