day36 重叠区间

452. 用最少数量的箭引爆气球

  1. 如果遇到重叠的气球,重叠区域会不断叠加,也就是重叠区间会缩小
  2. 如果新气球的起始位置不在重叠区域, 就射出一支箭
  3. 我们做的是区域重叠的问题,最后箭数要加一
  4. 因为是考虑重叠区间,所以只需要看start就行, end可以不进行排序
class Solution {
public:
    int findMinArrowShots(vector<vector<int>>& points) {
        sort(points.begin(), points.end(), [&](vector<int>&a, vector<int>&b){
            if(a[0] != b[0]) return a[0] < b[0];
            return a[1] < b[1];
        });
        int cnt = 0;
        int start = points[0][0];
        int end = points[0][1];
        for(int i=0; i<points.size(); i++){
           if(points[i][0] <= end){
               start = max(start, points[i][0]);
               end = min(end, points[i][1]);
           }else{
               cnt++;
               start = points[i][0];
               end = points[i][1];
           } 
        }
        return cnt+1;
    }
};

435. 无重叠区间
会议室的变形
结束越早越不容易跟别人重叠,结束越早,能够塞下的区间越多,同理去除的区间就越少

class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
         sort(intervals.begin(), intervals.end(), [&](vector<int>&a, vector<int>&b){
            return a[1] < b[1];
        });

        int end = intervals[0][1];
        int cnt = 0;
        for(int i=1; i<intervals.size(); i++){
            if(intervals[i][0] < end){
                cnt++;
            }else{
               end = intervals[i][1]; 
            }
        }
        return cnt; 
    }
};

56. 合并区间

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

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

思路一:遍历字符串 划分区间

  1. 记录每一个字符最后一次出现的位置
  2. 从头遍历字符串,记录下标为i时 [0.i]的所有字符最后出现的那个位置
  3. 如果当前位置正好时之前所有字符最后出现的那个位置,前面就可以归为一组
class Solution {
public:
    vector<int> partitionLabels(string s) {
     
        vector<int>a(26, -1);
        for(int i=0; i<s.size(); i++){   // 统计每个字符的最后位置
            a[s[i] - 'a'] = i;
        }
        vector<int>result;
        int start = -1;//start 是起始位置的前一个
        int end = a[s[0]-'a'];   //赋值第一个字符的最终 位置  c abdf 防止这种情况发生
        for(int i=0; i<s.size(); i++){
            if(i == end){ // 当前位置就是我们要找的边界
                result.push_back(end - start);
                start = i; 
                if(i+1 < s.size()) end = a[s[i+1] - 'a'];  //依旧是照顾开头第一个  
                //如果不符合这个条件就代表到了最后一个位置,下一步就是退出这个循环
            }else{
                end = max(a[s[i]-'a'], end);
            }
        }

    return result;
    }
};

简单版本

class Solution {
public:
    vector<int> partitionLabels(string S) {
        int hash[27] = {0}; // i为字符,hash[i]为字符出现的最后位置
        for (int i = 0; i < S.size(); i++) { // 统计每一个字符最后出现的位置
            hash[S[i] - 'a'] = i;
        }
        vector<int> result;
        int left = 0;
        int right = 0;
        for (int i = 0; i < S.size(); i++) {
            right = max(right, hash[S[i] - 'a']); // 找到字符出现的最远边界 
            //先进行边界的扩宽, 避免了 c baba的这样的尴尬  也解决了下一步的右边界的判断
            if (i == right) {
                result.push_back(right - left + 1);
                left = i + 1;
            }
        }
        return result;
    }
};

你可能感兴趣的:(哈希算法,算法)