435 无重叠区间
这种重叠问题都是要找有几个区间都是重合的,所以要用最小的右边界来判断之后的每一个。可以按照开始或者结束位置排序
先按照右边界end位置排序,然后循环掉所有重叠的,仅保留一个区间(最小右边界的)
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> Integer.compare(a[1], b[1]));
int count = 0;
int end = intervals[0][1];
int i = 0;
while (i < intervals.length) {
while (i < intervals.length && intervals[i][0] < end) {
i++;
}
count ++; // start>end, exceed current overlapping interval
if (i >= intervals.length) break;
end = intervals[i][1];
}
return intervals.length-count;
}
}
也是按照右边界end排序,重叠没有操作(end已经是最小右边界),不重叠就是新的区间,更新end位置
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals, (a, b) ->{
return Integer.compare(a[1], b[1]);
});
int count = 1;
int end = intervals[0][1];
for (int i = 1; i < intervals.length; i++) {
if (intervals[i][0] < end) {
continue;
} else {
end = intervals[i][1];
count++; // 独立不重叠区间个数
}
}
return intervals.length - count;
}
}
按照左边界排序,重叠就remove,不重叠就更新end,类似重叠区间射气球
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> {
return Integer.compare(a[0], b[0]);
});
int end = intervals[0][1];
int count = 0;
for (int i = 1; i < intervals.length; i++) {
if (intervals[i][0] < end) {
count++;
end = Math.min(end, intervals[i][1]);
} else {
end = intervals[i][1];
}
}
return count;
}
}
之前一直有问题是,没有在不重叠的时候更新end,只增长count,总是忘记终止位置。这是我的错误写法
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> {
return Integer.compare(a[0], b[0]);
});
int end = intervals[0][1];
int count = 1;
for (int i = 1; i < intervals.length; i++) {
if (intervals[i][0] < end) {
end = Math.min(end, intervals[i][1]);
} else {
count++; // 这里必须也更新end,总是忘记
// end = intervals[i][1];
}
}
return intervals.length - count;
}
}
763.划分字母区间
字母区间也是区间问题
class Solution {
public List<Integer> partitionLabels(String s) {
int[][] pos = new int[26][2];
int count = 1;
int firstIndex = s.charAt(0)- 'a'; // 第一个字母
for (int i = 0; i < s.length(); i++) {
if(s.charAt(i) - 'a' == firstIndex) {// 存储的第一个元素默认【0】是为0,所以要特殊处理
System.out.println("meet a at " + i);
pos[s.charAt(i) - 'a'][0] = 0;
pos[s.charAt(i) - 'a'][1] = i;
} else if (pos[s.charAt(i) - 'a'][0] == 0) { // 新出现字母
count++;
pos[s.charAt(i) - 'a'][0] = i;
pos[s.charAt(i) - 'a'][1] = i;
} else { // 已经出现过的字母,直接更新【1】
pos[s.charAt(i) - 'a'][1] = i;
}
}
//Arrays.sort(pos, (a, b) -> Integer.compare(a[0], b[0]));
Arrays.sort(pos, new Comparator<int[]>() { // 排序,因为会有很多字母没有出现过和第一个出现的字母都[0]为0,排序把所有没有出现过的都排在头部,删除
@Override
public int compare(int[] o1, int[] o2) {
if(o1[0]==o2[0]){
return o1[1] - o2[1];
}
return o1[0] - o2[0];
}
});
int first = pos.length-count;
int start = pos[first][0];
int end = pos[first][1];
List<Integer> res = new ArrayList<>();
for (int i = first; i < pos.length-1; i++) {
if (pos[i+1][0] < end) { // interleave
end = Math.max(end, pos[i+1][1]);
} else {
res.add(end-start+1);
start = pos[i+1][0];
end = pos[i+1][1];
}
}
res.add(end-start+1);
return res;
}
}
数组存储
class Solution {
public List<Integer> partitionLabels(String s) {
int[] lastOccurence = new int[26];
char[] chars = s.toCharArray();
for (int i = 0; i < chars.length; i++) {
lastOccurence[chars[i] - 'a'] = i;
}
List<Integer> result = new ArrayList<>();
int end = 0;
int count = 0;
for (int i = 0; i < chars.length; i++) {
end = Math.max(end, lastOccurence[chars[i] - 'a']);
count++;
if (i == end) {
result.add(count);
count = 0;
}
}
return result;
}
}
map存储
class Solution {
public List<Integer> partitionLabels(String s) {
Map<Character, Integer> lastOccurrence = new HashMap<>();
// Find the last occurrence index of each character
for (int i = 0; i < s.length(); i++) {
lastOccurrence.put(s.charAt(i), i);
}
List<Integer> partitions = new ArrayList<>();
int start = 0;
int end = 0;
// Iterate over the string to partition it
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
end = Math.max(end, lastOccurrence.get(c));
if (i == end) {
partitions.add(end - start + 1);
start = end + 1;
}
}
return partitions;
}
}
56. 合并区间
按照左边界排序,把所有点加入list,然后有重叠区间,就更新区间end为最大右边界,同时remove一个遍历过的节点,list转化array
class Solution {
public int[][] merge(int[][] intervals) {
Arrays.sort(intervals, (a,b) -> {
return Integer.compare(a[0], b[0]);
});
LinkedList<int[]> list = new LinkedList<>();
for (int i = 0; i < intervals.length;i ++) {
list.add(new int[] {intervals[i][0], intervals[i][1]});
}
int i = 1;
while(i != list.size()) {
if (list.get(i)[0] <= list.get(i-1)[1]) {
list.set(i-1, new int[] {list.get(i-1)[0],
Math.max(list.get(i-1)[1], list.get(i)[1])});
list.remove(i);
} else {
i++;
}
}
return list.toArray(new int[list.size()][]);
}
}
逻辑类似,重叠更新原数组中元素的终止位置,不是重叠区间就不更新,直接把上个区间加入答案
class Solution {
public int[][] merge(int[][] intervals) {
List<int[]> res = new LinkedList<>();
Arrays.sort(intervals, (a, b) -> {
return a[0] - b[0];
});
//Collections.addAll(intervalsList, intervals);
for (int i = 0; i < intervals.length-1; i++) {
if (intervals[i+1][0] <= intervals[i][1]) {
intervals[i][1] = Math.max(intervals[i+1][1], intervals[i][1]);
intervals[i+1][0] = intervals[i][0];
intervals[i+1][1] = intervals[i][1];
} else {
res.add(new int[] {intervals[i][0], intervals[i][1]});
}
}
res.add(new int[] {intervals[intervals.length-1][0], intervals[intervals.length-1][1]}); // 不要忘记最后一个
return res.toArray(new int[res.size()][]);
}
}
List to Array
public void listToArray2() {
String[] array = list.toArray(new String[list.size()]);
print(array);
}
array to list
public void arrayToList() {
List<String> list = new ArrayList<String>(Arrays.asList(array));
System.out.println(list.toString());
}
@Test
public void arrayToList2() {
List<String> list = new ArrayList<String>(array.length);
Collections.addAll(list, array);
}
感觉重叠数组类型问题也分为
- 所有都重叠,就需要每个数组开始位置在最小右边界内,更新end位置
- 数组接力式重叠,不断更新end位置