LeetCode Day38

54 阅读4分钟

435. 无重叠区间

给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。

示例 1: 输入: intervals = [[1,2],[2,3],[3,4],[1,3]] 输出: 1 解释: 移除 [1,3] 后,剩下的区间没有重叠。 示例 2: 输入: intervals = [ [1,2], [1,2], [1,2] ] 输出: 2 解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。 示例 3: 输入: intervals = [ [1,2], [2,3] ] 输出: 0 解释: 你不需要移除任何区间,因为它们已经是无重叠的了。

思路

  1. 排序:按照每个区间的开始时间对所有区间进行排序。
  2. 初始化:初始化两个变量:一个是 count,用于记录需要移除的区间数量,初始化为 0;另一个是 end,用于记录当前不重叠区间集合中最后一个区间的结束时间,初始化为第一个区间的结束时间。
  3. 遍历:接着,我们从第二个区间开始,遍历所有排序后的区间。
  • 如果当前区间与前一个区间重叠(即,当前区间的开始时间小于 end),则增加 count,并更新 end 为当前区间和前一个区间中结束时间较早的那一个(为了给后续区间留下更多空间)。
  • 如果当前区间不与前一个区间重叠,更新 end 为当前区间的结束时间。
  1. 结果:最后,count 将是需要移除的区间的最小数量。

题解

class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        int count = 0;
        
        if (intervals.empty() || intervals.size() == 1) {
            return 0;
        }

        sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b) {
            return a[0] < b[0];
        });
        
        int end = intervals[0][1];
        
        for (int i = 1; i < intervals.size(); ++i) {
            if (intervals[i][0] < end) {
                count++;
                end = min(end, intervals[i][1]);
            } else {
                end = intervals[i][1];
            }
        }
        
        return count;
    }
};

763. 划分字母区间

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。 注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。 返回一个表示每个字符串片段的长度的列表。

示例 1:输入:s = "ababcbacadefegdehijhklij" 输出:[9,7,8] 解释: 划分结果为 "ababcbaca"、"defegde"、"hijhklij" 。 每个字母最多出现在一个片段中。 像 "ababcbacadefegde", "hijhklij" 这样的划分是错误的,因为划分的片段数较少。 示例 2: 输入:s = "eccbbbbdec" 输出:[10]

思路

  1. 预处理:首先遍历整个字符串,用一个哈希表记录每个字符最后一次出现的位置。
  2. 初始化:设置两个变量 startend,分别表示当前片段的起始和结束位置。初始都为0。
  3. 遍历与更新:遍历字符串,对每个字符,更新 end 为当前片段所有字符最后出现位置的最大值,因为不断更新end,最后end=i的时候说明当前字符以及之前的所有字符都会在这个end的左边。
  4. 切割片段:每当遍历到的当前索引 i 等于 end 时,切割出一个新的片段,长度为 end - start + 1,并更新 startend + 1
  5. 返回结果:返回所有片段的长度组成的列表。

题解

class Solution {
public:
    vector<int> partitionLabels(string s) {
        unordered_map<char,int> last_occurrence;
        for(int i=0;i<s.size();i++){
            last_occurrence[s[i]]=i;
        }
        int end=0,start=0;
        vector<int> result;
        for (int i = 0; i < s.size(); ++i) {
            end = max(end, last_occurrence[s[i]]);
            if (i == end) {
                result.push_back(end - start + 1);
                start = end + 1;
            }
        }
        return result;
    }
};

56. 合并区间

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。

示例 1: 输入:intervals = [[1,3],[2,6],[8,10],[15,18]] 输出:[[1,6],[8,10],[15,18]] 解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6]. 示例 2: 输入:intervals = [[1,4],[4,5]] 输出:[[1,5]] 解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。

思路

  1. 排序:首先按照每个区间的起始时间对所有区间进行排序。
  2. 初始化:然后初始化一个空的结果数组 result
  3. 遍历与合并:接着,遍历排序后的区间。
  • 如果结果数组为空,或者当前区间与结果数组中最后一个区间没有重叠,直接将当前区间加入结果数组。
  • 如果当前区间与结果数组中最后一个区间有重叠,合并这两个区间。
  1. 返回结果:最后,返回结果数组 result

题解

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        // 按照区间的起始时间进行排序
        sort(intervals.begin(), intervals.end());
        
        // 初始化结果数组
        vector<vector<int>> result;
        
        // 遍历所有区间
        for (const auto& interval : intervals) {
            // 如果结果数组为空,或者当前区间与结果数组中最后一个区间没有重叠,
            // 直接将当前区间加入结果数组
            if (result.empty() || result.back()[1] < interval[0]) {
                result.push_back(interval);
            } else {
                // 否则,合并有重叠的区间
                result.back()[1] = max(result.back()[1], interval[1]);
            }
        }
        
        return result;  // 返回结果数组
    }
};