一维合并区间

Acwing 803.区间合并 数学 区间合并

题目描述
给定 n 个区间 [li,ri],要求合并所有有交集的区间。
注意如果在端点处相交,也算有交集。
输出合并完成后的区间个数。
例如:[1,3]和[2,6]可以合并为一个区间[1,6]。

输入格式
第一行包含整数n。
接下来n行,每行包含两个整数l和r。
输出格式
共一行,包含一个整数,表示合并区间完成后的区间个数。

数据范围
1≤n≤100000,
−109≤li≤ri≤109
样例
输入样例:

  1. 5
  2. 1 2
  3. 2 4
  4. 5 6
  5. 7 8
  6. 7 9

输出样例:

  1. 3

思路:按照每段区间的左端点排序,根据单调性遍历一遍数组找到所有能合并的区间并合并。
时间复杂度:O(nlogn)
空间复杂度 O(n)
注意:这里空间复杂度可以是O(1),因为题目只让求合并完后的区间个数,没有讲求出所有区间的具体内容。
上代码:

  1. import java.util.*;
  2. public class Main {
  3. public static void main(String[] args) {
  4. Scanner sc = new Scanner(System.in);
  5. int n = sc.nextInt();
  6. int[][] a = new int[n][2];
  7. for (int i = 0; i < n; i++) {
  8. a[i][0] = sc.nextInt();
  9. a[i][1] = sc.nextInt();
  10. }
  11. Arrays.sort(a, (o1, o2) -> o1[0] - o2[0]);
  12. int cnt = 0;
  13. int l = a[0][0], r = a[0][1];
  14. for (int i = 1; i < n; i++) {
  15. if (a[i][0] <= r) {
  16. r = Math.max(r, a[i][1]);
  17. } else {
  18. cnt++;
  19. l = a[i][0];
  20. r = a[i][1];
  21. }
  22. }
  23. cnt++;
  24. System.out.println(cnt);
  25. }
  26. }
  1. Arrays.sort(a, (o1, o2) -> o1[0] - o2[0]);
  2. // int cnt = 0;
  3. int n = a.length;
  4. int l = a[0][0], r = a[0][1];
  5. List<int[]> list = new ArrayList<>();
  6. for (int i = 1; i < n; i++) {
  7. if (a[i][0] <= r + 1) {
  8. r = Math.max(r, a[i][1]);
  9. } else {
  10. // cnt++;
  11. list.add(new int[]{l, r});
  12. l = a[i][0];
  13. r = a[i][1];
  14. }
  15. }
  16. // cnt++;
  17. // list.add(new int[]{l, r});
  18. // for (int[] b : list)
  19. // System.out.println(Arrays.toString(b));
  20. n = list.size();
  21. int[][] b = new int[n][2];
  22. for (int i = 0; i < n; i++) {
  23. b[i][0] = list.get(i)[0];
  24. b[i][1] = list.get(i)[1];
  25. }
  26. int max = 0;
  27. int cnt = 0;
  28. int left = 0;
  29. for (int i = 0, j = 0; j < n; j++) {
  30. max = Math.max(max, Math.min(c, b[j][1] - b[j][0] + 1));
  31. while (i < n && b[i][1] <= left + c - 1) {
  32. cnt += Math.min(left + c - 1, b[i][1]) - b[i][0] + 1;
  33. i++;
  34. max = Math.max(max, cnt);
  35. }
  36. // System.out.println(j + " " + max);
  37. }
  38. return max;

二维合并区间

759. 格子染色 数学 区间合并

题目描述:
在二维平面上有一个无限的网格图形,初始状态下,所有的格子都是空白的。
现在有 n 个操作,每个操作是选择一行或一列,并在这行或这列上选择两个端点网格,把以这两个网格为端点的区间内的所有网格染黑(包含这两个端点)。
问经过 n 次操作以后,共有多少个格子被染黑,重复染色同一格子只计数一次。
输入格式
第一行包含一个正整数 n。
接下来 n 行,每行包含四个整数 x1,y1,x2,y2,表示一个操作的两端格子坐标。
若 x1=x2则是在一列上染色,若 y1=y2则是在一行上染色。
保证每次操作是在一行或一列上染色。
输出格式
包含一个正整数,表示被染黑的格子的数量。
数据范围
1≤n≤10000,
−109≤x1,y1,x2,y2≤109
输入样例:

  1. 3
  2. 1 2 3 2
  3. 2 5 2 3
  4. 1 4 3 4

输出样例:

  1. 8

思路:相较于上题,问题从一维变成二维,而且还是两个二维的叠加。

  1. 读数据,行列分开
  2. 分别对行列的数据排序,按照位置,起止点的顺序进行排序
  3. 合并区间并计算区间大小(即统计被染黑的格子数量)
  4. 去重(行和列可能有重复的色块)
  5. 打印输出 ```java import java.util.*;

class Seg { int pos; int start; int end; Seg(int pos, int start, int end) { this.pos = pos; this.start = Math.min(start, end); this.end = Math.max(start, end); } } public class Main { public static void main(String[] sss) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); List rows = new ArrayList<>(); List cols = new ArrayList<>();

  1. for(int i = 0; i < n; i++) {
  2. int x1, y1, x2, y2;
  3. x1 = sc.nextInt();
  4. y1 = sc.nextInt();
  5. x2 = sc.nextInt();
  6. y2 = sc.nextInt();
  7. //行号相同
  8. if (x1 == x2) {
  9. rows.add(new Seg(x1, y1, y2));
  10. }
  11. //列号相同
  12. else {
  13. cols.add(new Seg(y1, x1, x2));
  14. }
  15. }
  16. //合并,数色块
  17. long ans = merge(rows) + merge(cols);
  18. for (int i = 0; i < rows.size(); i++) {
  19. Seg tmp = rows.get(i);
  20. System.out.println(tmp.pos + " " + tmp.start + " " + tmp.end);
  21. }
  22. for (int i = 0; i < cols.size(); i++) {
  23. Seg tmp = cols.get(i);
  24. System.out.println(tmp.pos + " " + tmp.start + " " + tmp.end);
  25. }
  26. //去掉重复色块
  27. for (int i = 0; i < rows.size(); i++) {
  28. Seg row = rows.get(i);
  29. for (int j = 0; j < cols.size(); j++) {
  30. Seg col = cols.get(j);
  31. if (row.start <= col.pos && row.end >= col.pos && col.start <= row.pos && col.end >= row.pos)
  32. ans--;
  33. }
  34. }
  35. System.out.println(ans);
  36. }
  37. static long merge(List<Seg> list) {
  38. List<Seg> res = new ArrayList<>();
  39. long sum = 0;
  40. list.sort((o1, o2) -> {
  41. if (o1.pos != o2.pos) return o1.pos - o2.pos;
  42. else if (o1.start != o2.start) return o1.start - o2.start;
  43. else return o1.end - o2.end;
  44. });
  45. int MIN = Integer.MIN_VALUE;
  46. for (int i = 0, j = 0; i < list.size();) {
  47. //递增j直至下一行/列
  48. while (j < list.size() && list.get(i).pos == list.get(j).pos) j++;
  49. int start = MIN + 1, end = MIN;
  50. for (int k = i; k < j; k++) {
  51. Seg tmp = list.get(k);
  52. if (tmp.start > end) {
  53. sum += end - start + 1;
  54. if (start != MIN+1) {
  55. res.add(new Seg(list.get(i).pos, start, end));
  56. }
  57. start = tmp.start;
  58. end = tmp.end;
  59. }
  60. else {
  61. end = Math.max(end, tmp.end);
  62. }
  63. }
  64. sum += end - start + 1;
  65. if (start != MIN + 1) res.add(new Seg(list.get(i).pos, start, end));
  66. i = j;
  67. }
  68. //注意这里不能这么写。。。
  69. //list = res;
  70. //得这么写才行
  71. list.clear();
  72. list.addAll(res);
  73. return sum;
  74. }

} ```