leetcode数组刷题(七)——区间集合处理

leetcode数组刷题(七)——区间集合处理

56、合并区间
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
多区间求并集,只需要按照区间的三类情况进行讨论即可。

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        if(intervals.size()==0) return {};
        vector<vector<int>> results;
        sort(intervals.begin(),intervals.end());
        results.push_back(intervals[0]);
        for(int i=1;i<intervals.size();++i){
            //int min = intervals[i][0];
            //int max = intervals[i][1];
            if(intervals[i][0]>results.back()[1]) results.push_back(intervals[i]);
            else if(intervals[i][0]<=results.back()[1]){
                if(intervals[i][1]>=results.back()[1]){
                    results.back()[1] = intervals[i][1];
                }
            }
        }
        return results;
    }
};

57、插入区间
给你一个 无重叠的 ,按照区间起始端点排序的区间列表
在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。
我自己用的就是分情况讨论的方法,用时击败99%,但是内存有点大,毕竟代码的变量有点多。测试了几次才通过的,原因第一个是for内嵌for不能用break打断,直接return,不然还会继续外循环。第二个原因是情况分类讨论不够全,之前一直忽视了continue的分类讨论,就是新的区间的左右范围都可能大于已有区间的范围的情况,需要另外考虑。

class Solution {
public:
    vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) {
        if(intervals.size()==0) return {newInterval};
        vector<vector<int>> results;
        vector<int> temp = intervals[0];
        for(int i=0;i<intervals.size();++i){
            if(newInterval[0]>intervals[i][1]){
                if(i==intervals.size()-1){
                    results.push_back(intervals[i]);
                    results.push_back(newInterval);
                    return results;判断区间大于已有区间
                }
                else{
                    results.push_back(intervals[i]);
                    continue;//找到区间左数插入的地方
                }
            }
            else if(newInterval[0]<=intervals[i][1]){
                //if(newInterval[0]>=intervals[i][0]){
                    temp[0] = min(intervals[i][0],newInterval[0]);
                    for(int j=i;j<intervals.size();++j){
                        if(newInterval[1]>intervals[j][1]){
                            if(j==intervals.size()-1){
                                temp[1] = newInterval[1];//判断区间大于已有区间
                                results.push_back(temp);
                                return results;
                            }
                            else continue;//区间右数
                        }
                        if(newInterval[1]<=intervals[j][1]){
                        if(newInterval[1]>=intervals[j][0]) {
                            temp[1] = intervals[j][1];
                            results.push_back(temp);
                            for(int k=j+1;k<intervals.size();++k){
                                results.push_back(intervals[k]);
                                //break;会继续外层循环有误,答案重复
                            }
                            return results;
                        }
                        else{
                            temp[1] = newInterval[1];
                            results.push_back(temp);
                            for(int k=j;k<intervals.size();++k){
                                results.push_back(intervals[k]);
                                //break;会继续外层循环有误,答案重复
                            }
                            return results;
                        }
                    }
                    }
                //}
            }
        }
        return results;
    }
};

官方的思路感觉更加清晰一些,就是直接分了三种情况,我是根据左右端点来考虑的,思路上烦琐了一些。

class Solution {
public:
    vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) {
        int left = newInterval[0];
        int right = newInterval[1];
        bool placed = false;
        vector<vector<int>> ans;
        for (const auto& interval: intervals) {
            if (interval[0] > right) {
                // 在插入区间的右侧且无交集
                if (!placed) {
                    ans.push_back({left, right});
                    placed = true;                    
                }
                ans.push_back(interval);
            }
            else if (interval[1] < left) {
                // 在插入区间的左侧且无交集
                ans.push_back(interval);
            }
            else {
                // 与插入区间有交集,计算它们的并集
                left = min(left, interval[0]);
                right = max(right, interval[1]);
            }
        }
        if (!placed) {
            ans.push_back({left, right});
        }
        return ans;
    }
};

78、子集
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
这题参考组合的思路,同样采用回宿,一种是循环体,一种是分是否采用当下元素分类的官方思路,分为两种代码如下:

class Solution {
public:
    vector<int> t;
    vector<vector<int>> ans;
    void dfs(vector<int>& nums, int cur) {
        if (cur == nums.size()) return;
        for(int i=cur;i<nums.size();i++){
            t.push_back(nums[i]);
            ans.push_back(t);
            dfs(nums,i+1);
            t.pop_back();
        }
    }
    vector<vector<int>> subsets(vector<int>& nums) {
        ans.push_back({});
        dfs(nums,0);
        return ans;
    }
};
class Solution {
public:
    vector<int> t;
    vector<vector<int>> ans;

    void dfs(int cur, vector<int>& nums) {
        if (cur == nums.size()) {
            ans.push_back(t);
            return;
        }
        t.push_back(nums[cur]);
        dfs(cur + 1, nums);
        t.pop_back();
        dfs(cur + 1, nums);
    }

    vector<vector<int>> subsets(vector<int>& nums) {
        dfs(0, nums);
        return ans;
    }
};

90、子集 II
给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
和所有问题一样的第二问,就是有重复元素,去重的语句可以参考组合或者全排列,其中代码一为参考组合,代码二为官方延续思路的需要加个bool判断变量,是否是第一个遇到的:

class Solution {
public:
    vector<int> t;
    vector<vector<int>> ans;
    void dfs(vector<int>& nums, int cur) {
        if (cur == nums.size()) return;
        for(int i=cur;i<nums.size();i++){
            if (i>cur && nums[i]==nums[i-1]) continue;
            t.push_back(nums[i]);
            ans.push_back(t);
            dfs(nums,i+1);
            t.pop_back();
        }
    }
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        ans.push_back({});
        dfs(nums,0);
        return ans;
    }
};
class Solution {
public:
    vector<int> t;
    vector<vector<int>> ans;

    void dfs(bool choosePre, int cur, vector<int> &nums) {
        if (cur == nums.size()) {
            ans.push_back(t);
            return;
        }
        dfs(false, cur + 1, nums);
        if (!choosePre && cur > 0 && nums[cur - 1] == nums[cur]) {
            return;
        }
        t.push_back(nums[cur]);
        dfs(true, cur + 1, nums);
        t.pop_back();
    }

    vector<vector<int>> subsetsWithDup(vector<int> &nums) {
        sort(nums.begin(), nums.end());
        dfs(false, 0, nums);
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浅笑相安

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值