【Leetcode贪心区间问题六】56.合并区间

Leetcode 56.合并区间

1.问题描述

在这里插入图片描述

2.解决方案

解法一:

这道题呢和452. 用最少数量的箭引爆气球 中的解法一很相似,可以说就基本一样的解题思路
1.维护一个temp,当找到一个和temp不重叠的区间时,我们会把temp加入结果集,并且更新temp为找到的这个区间,如果有重叠那就更新temp为并集,不加入结果集
2.循环结束别忘了把最后一个temp加入结果集

class Solution {
public:
    static bool cmp(vector<int>& a,vector<int>& b){
        //按区间左边界排序
        return a[0]<b[0];
    }
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        sort(intervals.begin(),intervals.end(),cmp);
        vector<vector<int>> ans;
        vector<int> temp=intervals[0];
        for(int i=1;i<intervals.size();i++){
            //temp和i的左边界肯定不用比了是有序的
            //不交叉[1,6] [7,8]
            if(intervals[i][0]>temp[1]){
                ans.push_back(temp);
                temp=intervals[i];
            }
            //交叉
            if(intervals[i][0]<=temp[1]){
                //[1,6] [2,5] 包含
                if(intervals[i][1]<=temp[1]){
                    continue;
                }
                //[1,6] [2,7] 交叉
                if(intervals[i][1]>temp[1]){
                    //temp=[1,7]
                    temp=vector<int>{temp[0],intervals[i][1]};
                }
            }
        }
        ans.push_back(temp);
        return ans;
    }
};

Java版本

class Solution {
    public int[][] merge(int[][] intervals) {
        //排序
        Arrays.sort(intervals, (o1,o2)->{
            if(o1[0]==o2[0]){
                return o1[1]-o2[1];
            }else{
                return o1[0]-o2[0];
            }
        });
        //遍历
        List<List<Integer>> list = new ArrayList<>();
        int left = intervals[0][0];
        int right = intervals[0][1];
        //考虑区间[left,right] [a,b]
        for(int i=1;i<intervals.length;i++){
            //a==left||a==right
            if(intervals[i][0]==left||intervals[i][0]==right){
                right = intervals[i][1];
                continue;
            }
            //left,right<a,b
            if(right<intervals[i][0]){
                List<Integer> t = new ArrayList<>();
                t.add(left);
                t.add(right);
                list.add(t);
                left = intervals[i][0];
                right = intervals[i][1];
                continue;
            }
            //left<a<right
            if(left<intervals[i][0]&&intervals[i][0]<right){
                //更新right
                if(intervals[i][1]>=right){
                    right = intervals[i][1];
                }
                //不更新
                else{}
                continue;
            }
        }
        //最后的left right
        List<Integer> t = new ArrayList<>();
        t.add(left);
        t.add(right);
        list.add(t);
        //转化
        int[][] ans = new int[list.size()][2];
        for(int i=0;i<list.size();i++){
            ans[i] = list.get(i).stream().mapToInt(Integer::intValue).toArray();
        }
        return ans;
    }
}


解法二:

思路呢和解法一其实差不多,和452. 用最少数量的箭引爆气球 中的解法二很相似
1.解法二相对于解法一呢,不维护temp,每次遍历到的区间和结果集的back()比较就好了
2.找到一个不交叉的就直接加入结果集
3.找到一个有交叉的也好办,直接更新为更大的那个右边界:
ans.back()[1]=max(ans.back()[1],intervals[i][1]);
4.当然为了代码简洁cmp函数用到了一个Lambda表达式

class Solution1 {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        sort(intervals.begin(),intervals.end(),[](const vector<int>& a,const vector<int>& b){return a[0]<b[0];});
        vector<vector<int>> ans;
        ans.push_back(intervals[0]);

        for(int i=1;i<intervals.size();i++){
            //i-1和i的左边界肯定不用比了是有序的
            //不交叉[1,6] [7,8]
            if(intervals[i][0]>ans.back()[1]){
                ans.push_back(intervals[i]);
            }
            //交叉[1,6] [2,5]或[1,6] [2,7]
            if(intervals[i][0]<=ans.back()[1]){
                ans.back()[1]=max(ans.back()[1],intervals[i][1]);
            }
        }
        return ans;
    }
};


总结解法一和解法二的两点不同:

1.解法一维护了temp,而解法二直接加入结果集每次跟结果集的最后一个区间比较
2.当遇到交叉的情况时不需要分情况是包含还是相交,直接取两个区间右边界较大的那个就好

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值