一道腾讯笔试题,附我的详细答案

做算法题,可能与我们平时编写业务逻辑的思维方式可能还不太一样。作算法题需要理解其中的原理,构思分析问题的方法,勤于总结,只有这样才能逐渐养成算法思维,而不是只有纯写业务逻辑的思维。

今天透过一道腾讯的笔试题:合并区间,体会算法思维对程序员的重要性。

合并区间

给出一个区间的集合,请合并所有重叠的区间。

示例 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 已刷题目总结:

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