435.无重叠区间
思路:从小到大排序集合,之后一旦重叠就抛弃右边的一个,然后用左边的一个跟下一个接着判断是否重叠,无法处理【1,2】【1,100】这样的区间,加了if函数通过了,但是无法大通过全部测试用例
尝试(部分AC)
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals,(a,b)->{
if(a[0] == b[0]) return a[1] - b[1];
return a[0]-b[0];
});
// Arrays.sort(intervals,(a,b) -> Integer.compare(a[0],b[0]));
int count = 0;
for(int i = 1;i < intervals.length; i++){
if(intervals[i][0] == intervals[i-1][0]){
intervals[i][1] = intervals[i-1][1];
count++;
continue;
}
if(intervals[i][0] < intervals[i-1][1]){
count++;
intervals[i][1] = intervals[i-1][1];
}
}
return count;
}
}
答案
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals, (a,b)-> {
return Integer.compare(a[0],b[0]);
});
int count = 1;
for(int i = 1;i < intervals.length;i++){
if(intervals[i][0] < intervals[i-1][1]){
intervals[i][1] = Math.min(intervals[i - 1][1], intervals[i][1]);
continue;
}else{
count++;
}
}
return intervals.length - count;
}
}
小结
- 取 区间1 和 区间2 右边界的最小值,因为这个最小值之前的部分一定是 区间1 和区间2 的重合部分,如果这个最小值也触达到区间3,那么说明 区间 1,2,3都是重合的。
- 卡尔的思路是反过来的,先计算没有交叉的区间个数,再用总数去减,就得到了结果
763.划分字母区间
思路:把字符串转换为数字吗?ASCII码转出来还是不知道怎么处理,我想的是扫描字符串,把相同字母的离得最远的两个当作左右边界,排序之后,遍历融合区间,之后遍历集合,把数字加起来,我怎么知道哪个是末尾的a呢,啊哈,不断取最大的下标
尝试(有思路,代码写不出来)
class Solution {
public List<Integer> partitionLabels(String s) {
int[][] temp = createIntervals(s);
// 讲temp数组排序
Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
// 遍历temp数组,把相交的区间融合在一起,放入到新的数组
List<int[][]> merged = new ArrayList<>();
for (int i =1; i < temp.length; i++) {
if (temp[i][0] < temp[i-1][1]) {
merged.add(new int[temp[i-1][0],temp[i][1]]);
}else{
merged.add(new int[temp[i][0],temp[i][1]]);
}
}
// 将结果转换为数组
int[][] mergedIntervals = merged.toArray(new int[merged.size()][]);
// 遍历新的数组,挨个取出区间长度+1,组成结果数组
int result = 0;
for(int[][] p : mergedIntervals){
result +=p[1]-p[0]+1;
}
return result;
}
public static int[][] createIntervals(String str) {
HashMap<Character, List<Integer>> map = new HashMap<>();
int[][] temp = new int[str.length()][2];
// 遍历字符串,记录每个字符的下标
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
map.putIfAbsent(c, new ArrayList<>());
map.get(c).add(i);
}
// 根据下标列表创建区间
int index = 0; // temp数组的索引
for (List<Integer> indices : map.values()) {
if (indices.size() > 1) {
// 只有当有多个相同字符时才创建区间
temp[index][0] = indices.get(0); // 区间的左边界
temp[index][1] = indices.get(indices.size() - 1); // 区间的右边界
index++;
}
}
// 如果需要,可以截断temp数组以去除未使用的部分
int[][] result = new int[index][2];
System.arraycopy(temp, 0, result, 0, index);
return result;
}
}
答案
class Solution {
public List<Integer> partitionLabels(String S) {
List<Integer> list = new LinkedList<>();
int[] edge = new int[26];
char[] chars = S.toCharArray();
for (int i = 0; i < chars.length; i++) {
edge[chars[i] - 'a'] = i;
}
int idx = 0;
int last = -1;
for (int i = 0; i < chars.length; i++) {
idx = Math.max(idx,edge[chars[i] - 'a']);
if (i == idx) {
list.add(i - last);
last = i;
}
}
return list;
}
}
小结
- 哥们,你的思路好像可行,但是不够简洁,卡尔的思路是,先遍历字符串,记录所有字符的最远位置,存入edge数组,之后遍历edge数组,目标是找到分割线,挨个取出元素与当前idx比较,如果元素比当前idx大,就更新idx,直到遍历到idx对应的下标处,把(i-last)存入结果list,更新last
- 每次遇到新字母【new】,就要走到这个字母的最远处,这样才能保证所有【new】只出现在一个区间
- 记录字母最远的边界,用【int[] edge = new int[26];】和【edge[chars[i] - 'a']】
56.合并区间
思路:以为很简单,遇到重叠的,叠一下加入结果数组,不重叠的,就把前一个加入结果数组
尝试(标题4)
class Solution {
public int[][] merge(int[][] intervals) {
Arrays.sort(intervals,(a,b)->{
return a[0]-b[0];
});
List<int[]> result = new LinkedList<>();
if(intervals.length == 1) return intervals;
for(int i =1; i< intervals.length; i++){
if(intervals[i][0]<=intervals[i-1][1]){
intervals[i][0] = Math.min(intervals[i][0],intervals[i-1][0]);
intervals[i][1] = Math.max(intervals[i][1],intervals[i-1][1]);
result.add(new int[]{intervals[i][0], intervals[i][1]});
}else{
if(i==1){
result.add(new int[]{intervals[i-1][0], intervals[i-1][1]});
}else{
result.add(new int[]{intervals[i][0], intervals[i][1]});
}
}
}
return result.toArray(new int[result.size()][]);
}
}
答案
class Solution {
public int[][] merge(int[][] intervals) {
List<int[]> res = new LinkedList<>();
//按照左边界排序
Arrays.sort(intervals, (x, y) -> Integer.compare(x[0], y[0]));
//initial start 是最小左边界
int start = intervals[0][0];
int rightmostRightBound = intervals[0][1];
for (int i = 1; i < intervals.length; i++) {
//如果左边界大于最大右边界
if (intervals[i][0] > rightmostRightBound) {
//加入区间 并且更新start
res.add(new int[]{start, rightmostRightBound});
start = intervals[i][0];
rightmostRightBound = intervals[i][1];
} else {
//更新最大右边界
rightmostRightBound = Math.max(rightmostRightBound, intervals[i][1]);
}
}
res.add(new int[]{start, rightmostRightBound});
return res.toArray(new int[res.size()][]);
}
}
小结
- 定义左右边界,遍历数组,左右边界跟下一个区间有相交,就更新右边界,否则把左右边界构成的区间加入结果数组,把下一个区间当作左右边界,最后要加上左右边界