解法1:经典数组二分,思路就是找到一个刚好比他小的数字,插后面,然后考虑前后合并,细节部分很多,贼恶心。
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
class SummaryRanges {
List<int[]> list = new ArrayList<>();
Set<Integer> set = new TreeSet<>();
public SummaryRanges() {
}
public void addNum(int val) {
if (list.isEmpty()) {
list.add(new int[]{val, val});
set.add(val);
return;
}
if (set.contains(val)) {
return;
}
set.add(val);
int l = 0;
int r = list.size() - 1;
while (l <= r) {
int mid = (l + r) >> 1;
if (val > list.get(mid)[1]) {
l = mid + 1;
} else {
r = mid - 1;
}
}
l--;
int[] bef = {0, 0};
int[] next = {0, 0};
if(l != -1) {
bef = list.get(l);
}
if (l != list.size() - 1) {
next = list.get(l + 1);
}
// 并前,可能并后
if (l != -1 && val == bef[1] + 1) {
bef[1]++;
if (l != list.size() - 1) {
if (next[0] == bef[1] + 1) {
bef[1] = next[1];
list.remove(l + 1);
}
}
list.set(l, bef);
} // 只并后
else if (val == next[0] - 1) {
next[0] = val;
list.set(l + 1, next);
} // 啥也不并
else {
list.add(l + 1, new int[]{val, val});
}
}
public int[][] getIntervals() {
return list.toArray(new int[list.size()][]);
}
}
解法2:学习到了treemap的二分写法,宫水三叶yyds,直接抄了
class SummaryRanges {
TreeSet<int[]> ts = new TreeSet<>((a, b)->a[0]-b[0]);
int[] head = new int[]{-10, -10}, tail = new int[]{10010, 10010};
public SummaryRanges() {
ts.add(head);
ts.add(tail);
}
public void addNum(int val) {
int[] cur = new int[]{val, val};
int[] prev = ts.floor(cur);
int[] next = ts.ceiling(cur);
if ((prev[0] <= val && val <= prev[1]) || (next[0] <= val && val <= next[1])) {
// pass
} else if (prev[1] + 1 == val && next[0] - 1 == val) {
prev[1] = next[1];
ts.remove(next);
} else if (prev[1] + 1 == val) {
prev[1] = val;
} else if (next[0] - 1 == val) {
next[0] = val;
} else {
ts.add(cur);
}
}
public int[][] getIntervals() {
// using ceiling
// int n = ts.size();
// int[][] ans = new int[n - 2][2];
// int[] cur = head;
// for (int i = 0; i < n - 2; i++) {
// ans[i] = ts.ceiling(new int[]{cur[0] + 1, cur[1] + 1});
// cur = ans[i];
// }
// return ans;
// using iterator
int n = ts.size();
int[][] ans = new int[n - 2][2];
Iterator<int[]> iterator = ts.iterator();
iterator.next();
for (int i = 0; i < n - 2; i++) ans[i] = iterator.next();
return ans;
}
}
作者:AC_OIer
链接:https://leetcode-cn.com/problems/data-stream-as-disjoint-intervals/solution/gong-shui-san-xie-yi-ti-shuang-jie-er-fe-afrk/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解法3:经典treeset暴力,针对进阶题的做法
写了一段奇奇怪怪的代码,本质就是暴力瞎搞,
先用set过滤掉重复的数字,然后getIntervals的时候合并一遍,
st为左边界,ed为右边界,next为下一个元素。
如果next为ed+1,更新ed的值,这里将next = -2是为了在后面没有其他元素的时候,能在添加答案后退出循环;
否则将next传递给st,因为设置了next = -2的退出条件,所以可以保证这个next一定会被添加到答案中;
时间复杂度:添加是logn,查找是n。
class SummaryRanges {
TreeSet<Integer> set = new TreeSet<>();
public SummaryRanges() {
}
public void addNum(int val) {
set.add(val);
}
public int[][] getIntervals() {
// 如果存在大量合并,并且与数据流的大小相比,不相交区间的数量很小
// 可以在获取答案的时候合并
List<int[]> ans = new ArrayList<>();
final Iterator<Integer> iterator = set.iterator();
Integer st = -1;
while (st != -2) {
if (st == -1) {
if (iterator.hasNext()) {
st = iterator.next();
} else {
break;
}
}
Integer ed = st;
Integer next = -2;
while (true) {
if (iterator.hasNext()) {
next = iterator.next();
if(next == ed + 1) {
ed ++;
next = -2;
} else {
break;
}
continue;
}
break;
}
ans.add(new int[]{st, ed});
st = next;
}
return ans.toArray(new int[ans.size()][]);
}
}
方法4:并查集3解
贴个牛人的解法,看了看确实牛逼
https://leetcode-cn.com/problems/data-stream-as-disjoint-intervals/solution/tong-ge-lai-shua-ti-la-yi-ti-san-jie-mo-tpqtc/