5分钟
LeetCode算法手记:986.区间列表的交集
给定两个由一些闭区间组成的列表,firstList 和 secondList ,其中 firstList[i] = [start i, end i] 而 secondList[j] = [start j, end j] 。
每个区间列表都是成对不相交的,并且已经排序 。返回这两个区间列表的交集 。
形式上,闭区间 [a, b](其中 a <= b)表示实数 x 的集合,而 a <= x <= b 。
两个闭区间的交集是一组实数,要么为空集,要么为闭区间。例如,[1, 3] 和 [2, 4] 的交集为 [2, 3] 。
示例 1:
输入:firstList = [[0,2],[5,10],[13,23],[24,25]], secondList = [[1,5],[8,12],[15,24],[25,26]]
输出:[[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]]
示例 2:
输入:firstList = [[1,3],[5,9]], secondList = [ ]
输出:[ ]
示例 3:
输入:firstList = [], secondList = [[4,8],[10,12]]
输出:[ ]
示例 4:
输入:firstList = [[1,7]], secondList = [[3,10]]
输出:[[3,7]]
提示:
0 <= firstList.length, secondList.length <= 1000
firstList.length + secondList.length >= 1
0 <= start i < end i <= 109
end i < start i+1
0 <= start j < end j <= 109
end j < start j+1
思路
维护双指针i,j,各自指向两个区间列表,对应[starti,endi]和[startj,endj]。
其实如果两个区间[starti,endi]和[startj,endj]存在交集,则必然遵循这样的规律:
-
- endj必然大于等于starti,同时,endi必然大于等于startj。
-
- 交集的开闭区间必然为[max(starti,startj),min(endi,endj)]。
同时,对于区间的末尾,需要做判断:
-
如果endi在endj之后,说明区间i向后延伸更长的范围,可能会和下一个区间j有交集,此时需要判断下一个j区间。
-
如果endj在endi之后,说明区间j向后延伸更长的范围,可能会和下一个区间i有交集,此时需要判断下一个i区间。
思路递推
以实例一中的firstList = [[0,2],[5,10],[13,23],[24,25]], secondList = [[1,5],[8,12],[15,24],[25,26]]为例:
- 初始化,i = 0,j = 0。
- [starti,endi]对应[0,2],[startj,endj]对应[1,5],发现endj大于等于starti且endi大于等于startj,得到相交区间[max(starti,startj),min(endi,endj)] = [1,2],加入结果集。
- 此时endj大于endi,说明区间j向后延伸更长的范围,可能会和下一个区间i有交集,此时需要判断下一个i区间,因此i++向后递进。
- i = 1,j = 0。
- [starti,endi]对应[5,10],[startj,endj]对应[1,5],发现endj大于等于starti且endi大于等于startj,得到相交区间[max(starti,startj),min(endi,endj)] = [5,5],加入结果集。
- 此时endi大于endj,说明区间i向后延伸更长的范围,可能会和下一个区间j有交集,此时需要判断下一个j区间,因此j++向后递进。
- i = 1,j = 1。
- [starti,endi]对应[5,10],[startj,endj]对应[8,12],发现endj大于等于starti且endi大于等于startj,得到相交区间[max(starti,startj),min(endi,endj)] = [8,10],加入结果集。
- 此时endj大于endi,说明区间j向后延伸更长的范围,可能会和下一个区间i有交集,此时需要判断下一个i区间,因此i++向后递进。
- i = 2,j = 1。
- [starti,endi]对应[13,23],[startj,endj]对应[8,12],发现不满足endj大于等于starti且endi大于等于startj,无法得到相交区间。
- 此时endi大于endj,说明区间i向后延伸更长的范围,可能会和下一个区间j有交集,此时需要判断下一个j区间,因此j++向后递进。
- i = 2,j = 2。
- [starti,endi]对应[13,23],[startj,endj]对应[15,24],发现endj大于等于starti且endi大于等于startj,得到相交区间[max(starti,startj),min(endi,endj)] = [15,23],加入结果集。
- 此时endj大于endi,说明区间j向后延伸更长的范围,可能会和下一个区间i有交集,此时需要判断下一个i区间,因此i++向后递进。
- i = 3,j = 2。
- [starti,endi]对应[24,25],[startj,endj]对应[15,24],发现endj大于等于starti且endi大于等于startj,得到相交区间[max(starti,startj),min(endi,endj)] = [24,24],加入结果集。
- 此时endi大于endj,说明区间i向后延伸更长的范围,可能会和下一个区间j有交集,此时需要判断下一个j区间,因此j++向后递进。
- i = 3,j = 3。
- [starti,endi]对应[24,25],[startj,endj]对应[25,26],发现endj大于等于starti且endi大于等于startj,得到相交区间[max(starti,startj),min(endi,endj)] = [25,25],加入结果集。
- 此时endj大于endi,说明区间j向后延伸更长的范围,可能会和下一个区间i有交集,此时需要判断下一个i区间,因此i++向后递进。
- i = 4,j = 3,由于i已经超越数组边界,退出循环。
- 最终结果为[[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]]
代码实现
public static int[][] intervalIntersection(int[][] firstList, int[][] secondList) {
int fLength = firstList.length,sLength = secondList.length;
int i = 0,j = 0;
List<int[]> list = new ArrayList<>();
while (i < fLength && j < sLength){
int startI = firstList[i][0],endI = firstList[i][1];
int startJ = secondList[j][0],endJ = secondList[j][1];
//只有endJ大于等于startI 且 startJ 大于等于endI 才能证明两者存在交集
if (endJ >= startI && endI >= startJ ){
list.add(new int[]{Math.max(startI,startJ),Math.min(endI,endJ)});
}
if (endJ < endI){
j++;
} else {
i++;
}
}
return list.toArray(new int[0][0]);
}
public static void test(){
int[][] ints = intervalIntersection(new int[][]{{0, 2}, {5, 10}, {13, 23}, {24, 25}}, new int[][]{{1, 5}, {8, 12}, {15, 24}, {25, 26}});
for (int[] anInt : ints) {
System.out.println(Arrays.toString(anInt));
}
}