区间列表的交集[二分法 + 双指针 + 逆向思维]

前言

区间列表的交集关键问题在于两个区间的关系判断,可以逆向思维来进行关系分类处理;该题还可以练习二分法和双指针法。

一、区间列表的交集

在这里插入图片描述

二、区间关系分类

1、双指针+逆向思维

// 二分其实也没太必要。
class IntervalIntersection2 {
    /*
    target:找两个区间数组重叠的区间。两个区间数组各自有序。
    有序区间,可二分查找第一个区间数组的第一个区间在第二个区间数组的位置。
    然后双指针判断重合区间,知道一个指针指到了一个区间数组的末尾。
    如何判断区间的关系?找到存在区间重叠的情况,就能取两者重叠区间。
     */
    public int[][] intervalIntersection(int[][] firstList, int[][] secondList) {
        // 取两个数组的长度。
        int m = firstList.length, n = secondList.length;
        // 一旦一个数组为空,则肯定没有重合区间。
        if (m == 0 || 0 == n) return new int[][]{};
        // 初始化两个区间数组的指针。
        int fp = 0, sp = 0;
        List<int[]> rs = new ArrayList<>();
        while (fp < m && n > sp) {
            // 区间关系,分类处理。
            // 存在重叠区间。处理方式,因为不存在重叠区间比较好选择,所以! + 不存在区间的情况 == 逆向思维。
            if (!(firstList[fp][1] < secondList[sp][0] || firstList[fp][0] > secondList[sp][1])) {
                int front = firstList[fp][0];
                if (front < secondList[sp][0]) front = secondList[sp][0];
                int behind = firstList[fp][1];
                if (behind > secondList[sp][1]) behind = secondList[sp][1];

                rs.add(new int[]{front, behind});
            }
            // 更新fp 和 sp。
            if (firstList[fp][1] > secondList[sp][1]) ++sp;
            else ++fp;
        }
        return rs.toArray(new int[0][]);
    }
}

2、二分提速+双指针+逆向思维

//  区间列表的交集。
public class IntervalIntersection {
    /*
    target:找两个区间数组重叠的区间。两个区间数组各自有序。
    有序区间,可二分查找第一个区间数组的第一个区间在第二个区间数组的位置。
    然后双指针判断重合区间,知道一个指针指到了一个区间数组的末尾。
    如何判断区间的关系?找到存在区间重叠的情况,就能取两者重叠区间,区间重叠判断情况太多,可逆向思维判断。
     */
    public int[][] intervalIntersection(int[][] firstList, int[][] secondList) {
        // 取两个数组的长度。
        int m = firstList.length, n = secondList.length;
        // 一旦一个数组为空,则肯定没有重合区间。
        if (m == 0 || 0 == n) return new int[][]{};
        // 初始化两个区间数组的指针。
        int fp = 0, sp = binarySearch(secondList, firstList[0][0]);
        List<int[]> rs = new ArrayList<>();
        while (fp < m && n > sp) {
            // 区间关系,分类处理。
            // 存在重叠区间。处理方式,因为不存在重叠区间比较好选择,所以! + 不存在区间的情况 == 逆向思维。
            if (!(firstList[fp][1] < secondList[sp][0] || firstList[fp][0] > secondList[sp][1])) {
                int front = firstList[fp][0];
                if (front < secondList[sp][0]) front = secondList[sp][0];
                int behind = firstList[fp][1];
                if (behind > secondList[sp][1]) behind = secondList[sp][1];

                rs.add(new int[]{front, behind});
            }
            // 更新fp 和 sp。
            if (firstList[fp][1] > secondList[sp][1]) ++sp;
            else ++fp;
        }
        return rs.toArray(new int[0][]);
    }

    // 插入式二分,插左。找target在arr[][1]的位置。
    private int binarySearch(int[][] arr, int target) {
        int low = 0, high = arr.length;

        while (low < high) {
            int mid = low + (high - low >>> 1);
            int midVal = arr[mid][1];

            if (target > midVal) low = mid + 1;
            else high = low;
        }
        return high;
    }
}

总结

1)二插入插左法。
2)双指针。
3)逆向思维解决区间关系分类。

参考文献

[1] LeetCode 区间列表的交集

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值