Day38 LeetCode 452. 用最少数量的箭引爆气球 435. 无重叠区间 763. 划分字母区间 56. 合并区间

 题目:452. 用最少数量的箭引爆气球 - 力扣(LeetCode)

思路:

         局部最优:当气球重叠在一起,一起射,所用弓箭数量最少;全局最优:将所有气球引爆所用弓箭数量最少。

        步骤:为了使气球重叠在一起,需要先对气球进行排序。对气球按照左边界进行从小到大排序。如果气球不重叠,则第i个气球的左边界大于第i-1个气球的右边界,则需要一个弓箭;如果气球重叠,则第i个气球的左边界小于等于第i-1个气球的右边界,则不断更新重叠气球的最小有边界。

代码:

class Solution {
public:
    static bool cmp(vector& a, vector& b){
        return a[0] < b[0];//按照气球开始坐标 x(start)从小到大排序
    }
    int findMinArrowShots(vector>& points) {
        if(points.size() == 0) return 0;
        sort(points.begin(), points.end(), cmp);
        int result = 1;//定义需要的弓箭数目:如果气球个数不为0,至少需要l个弓箭
        for(int i = 1; i < points.size(); i++){
            //如果第i个气球的左边界大于第i-1个气球的右边界,说明需要一个弓箭来引爆以第i个气球为首的气球集合(如果几个气球重叠的话)
            if(points[i][0] > points[i - 1][1]){
                result++;
            }
            //如果第i个气球的左边界小于等于第i-1个气球的右边界,说明两个气球重叠在一起,则更新第i个气球的右边界(取两个气球右边界的最小值)
            else{
                points[i][1] = min(points[i][1], points[i - 1][1]);
            }
        }
        return result;
    }
};

题目:435. 无重叠区间 - 力扣(LeetCode)

思路:和 452.使用最少数量的箭引爆气球 这题类似。

        先根据区间的左边界进行由小到大进行排序,然后判断重叠区间,对重叠区间的数量进行统计,最后得到的重叠区间数量就是我们要移除区间的最小数量。

代码:

class Solution {
public:
    static bool cmp(vector& a, vector& b){
        return a[0] < b[0];//将区间按照左边界进行由小到大排序
    }
    int eraseOverlapIntervals(vector>& intervals) {
        if(intervals.size() == 0) return 0;
        sort(intervals.begin(), intervals.end(), cmp);
        int count = 0;//记录区间重叠个数
        for(int i = 1; i < intervals.size(); i++){
            if(intervals[i][0] < intervals[i - 1][1]){
                count++;//当前区间的左边界小于前一个区间的右边界,说明两个区间重叠,count加1
                //更新重叠区间的右边界,始终保持重叠区间的右边界是最小的
                intervals[i][1] = min(intervals[i][1], intervals[i - 1][1]);
            }
        }
        return count;
    }
};

题目:763. 划分字母区间 - 力扣(LeetCode)

思路:

        在遍历的过程中相当于是要找每一个字母的边界,如果找到之前遍历过的所有字母的最远边界,说明这个边界就是分割点了。此时前面出现过所有字母,最远也就到这个边界了。 

先统计每一个字符出现的最远边界。遍历字符,不断更新字符出现的最远边界,如果当前遍历到最远边界,证明来到了区间的分割点。

代码:

class Solution {
public:
    vector partitionLabels(string s) {
        int hash[27] = {0};//hash数组用来统计字符出现的最远下标距离
        vector result;
        for(int i = 0; i < s.size(); i++){// 统计每一个字符最后出现的位置
            hash[s[i] - 'a'] = i;//不断更新字符出现的距离,最后得到的一定是字符的最远下标
        }

        int left = 0;//定义片段左区间
        int right = 0;//定义片段右区间
        for(int i = 0; i < s.size(); i++){
            right = max(hash[s[i] - 'a'], right);//不断更新片段中字符的最远下标,找到字符出现的最远边界
            if(i == right){//如果遍历到字符最远边界,满足最长的划分片段
                result.push_back(right - left + 1);
                left = i + 1;
            }
            
        }
        return result;
    }
};

题目:56. 合并区间 - 力扣(LeetCode)

思路:

先排序,让所有的相邻区间尽可能的重叠在一起 ,按照左边界从小到大排序之后,如果 intervals[i][0]<= intervals[i - 1][1],则一定有重叠。如果重叠就合并区间,其实就是用合并区间后左边界和右边界,作为一个新的区间,加入到result数组里就可以了。如果没有合并就把原区间加入到result数组。

代码:

class Solution {
public:
    static bool cmp(vector& a, vector& b){
        return a[0] < b[0];
    }
    vector> merge(vector>& intervals) {
        sort(intervals.begin(), intervals.end(), cmp);
        vector> result;
        result.push_back(intervals[0]);

        for(int i = 1; i < intervals.size(); i++){
            if(intervals[i][0] <= result.back()[1]){//发现重叠区间
            //合并区间:只需要更新右边界,因为左边界已经是由小到大排好序了的
                result.back()[1] = max(intervals[i][1], result.back()[1]);//取最大右边界
            }else{
                result.push_back(intervals[i]);//如果区间不重叠
            }
        }
        return result;
    }
};

你可能感兴趣的:(算法,leetcode,算法,数据结构,贪心算法)