贪心算法
435.无重叠区间
解题思路:
重叠区间套路题: 从下标为1的位置开始比较重叠情况, 并进行处理
- 若无重叠, 则应当使用新区间向后比较
- 若有重叠区间, 则应该删除右端点值较大的区间, 使用右端点值较小的区间去向后比较, 这样能防止更多的重叠区间
代码:
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals, (c1,c2)->c1[0]-c2[0]);
// 从第二个元素开始判断是否有重叠区间
LinkedList<int[]> list = new LinkedList<>();
int ans = 0;
list.add(intervals[0]);
for(int i=1; i<intervals.length; i++) {
int[] pre = list.getLast();
// 无重叠
if(pre[1] <= intervals[i][0]){
list.add(intervals[i]);
}else {
// 判断重叠情况, 若包含当前区间, 应当将pre设置为当前区间
// 若不包含当前区间, 应当删除的是当前区间, 因为其能防止后面的包含
if(pre[1] > intervals[i][1]) {
list.add(intervals[i]);
}
// 有重叠就至少需要移除一个
ans++;
}
}
return ans;
}
}
763.划分字母区间
解题思路:
- 先用一个哈希表统计每个字符最后出现的位置
- 从头开始遍历, 在遍历过程中不断更新遍历终点为当前区间中字符出现的最远位置
- 遍历到最后, 若遍历位置等于其前面所有字符出现的最远位置, 则代表该位置之前的区间可以划分为一个区间
代码:
class Solution {
public List<Integer> partitionLabels(String s) {
// 统计当前字符最后一次出现的位置
HashMap<Character, Integer> map = new HashMap<>();
char[] ch = s.toCharArray();
for(int i=0; i<ch.length; i++) {
map.put(ch[i], i);
}
List<Integer> list = new ArrayList<>();
int start = 0, end = map.get(ch[0]);
while(start < ch.length) {
int i = start;
end = map.get(ch[start]);
for(i = start; i<=end; i++) {
end = Math.max(end, map.get(ch[i]));
}
list.add(i - start);
start = i;
}
return list;
}
}
56.合并区间
解题思路: 合并区间套路题
- 用list收集重叠区间, 从下标1开始, 对每个区间都和前一个区间进行合并
代码:
class Solution {
public int[][] merge(int[][] intervals) {
// 先排序
Arrays.sort(intervals, (c1,c2)->c1[0]-c2[0]);
// 合并区间到list, 组后再转为二维数组
LinkedList<int[]> list = new LinkedList<>();
list.add(intervals[0]);
for(int i=1; i<intervals.length; i++) {
int[] pre = list.getLast();
// 没有重叠区间
if(pre[1] < intervals[i][0]) {
list.add(intervals[i]);
}else {
list.removeLast();
list.add(new int[]{Math.min(pre[0], intervals[i][0]), Math.max(pre[1], intervals[i][1])});
}
}
return list.toArray(new int[list.size()][]);
}
}