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

 

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