面试150——区间

并集

在这里插入图片描述
合并区间思路
合并区间是区间间取并集,最终返回所有的并集。按照左端点升序排序,不断更新右端点最大值,直到无法更新,则开新区间。
代码

class Solution {
    public int[][] merge(int[][] intervals) {
        int n = intervals.length;
        if (n == 0) return new int[0][0];
        Arrays.sort(intervals, (a, b)->(a[0] - b[0]));
        List<int[]> list = new ArrayList<>();
        for (int i = 0; i < n; i ++) {
            if (i == 0 || list.getLast()[1] < intervals[i][0]) {
                list.add(new int[] {intervals[i][0], intervals[i][1]}); // 没去可以合并的区间,则开新区间
            } else {
                list.getLast()[1] = Math.max(list.getLast()[1], intervals[i][1]); // 合并区间
            }
        }
        return list.toArray(new int[list.size()][2]);
    }
}

交集

在这里插入图片描述
交集思路
每次射都要射相交的部分,要使用的箭最少。则找到所有区间最少得相交的划分。每个区间在所有区间尽可能囊括多的有公共部分的区间,则这个区间的右边要大于囊括区间的左边。一种贪心的思路,右边越短的,希望囊括右边越短的。所以将右边按照升序排序。
代码

// 每次射希望能够射得最多,也就是每次找到重叠最多的气球
// 重叠部分是由一段区间最早结束的部分能覆盖多少决定的,所以按照区间右端点排序
class Solution {
    public int findMinArrowShots(int[][] points) {
        if (points == null) return 0;
        int n = points.length;
        if (n == 0) return 0;
        Arrays.sort(points, (a, b) -> Integer.compare(a[1], b[1]));
        int res = 0, right = 0;
        for (int i = 0; i < n; i ++) {
            if (i == 0 || right < points[i][0]) {
                res ++;
                right = points[i][1];
            }
        }
        return res;
    }
}

2054. 两个最好的不重叠活动

在这里插入图片描述
思路
假设当前选择第二个event,其开始时间是startTime。那么选择第一个event,他的endTime一定需要小于startTime。无所谓startTime,则按照endTime排序。
问题转化为对于startTime_i在0~i-1所有事件中找到endTime小于startTime_i的value最大值。如果这样操作时间复杂度是O(n^2)。
接下来思考元素是按照endTime排序,如果后面的元素的value小于前面的元素,这样的元素是肯定不会被选为第一个元素的所以直接pass。
这样搜索空间变成了一个递增序列,则可以使用二分查找。
代码


class Solution {
    public int maxTwoEvents(int[][] events) {
        Arrays.sort(events, (a, b)-> a[1] - b[1]);
        ArrayList<int[]> st = new ArrayList<>();
        st.add(new int[]{0, 0, 0});
        int ans = 0;
        for (int[] e : events) {
            int start = e[0], end = e[1], v = e[2];
            int prev = search(st, start);
            ans = Math.max(ans, v + prev);
            if (v > st.getLast()[2]) {
                st.add(new int[]{start, end, v});
            }
        }
        return ans;
    }
    // 找到start前值最大的,左半段
    int search(List<int[]> st, int start) {
        int l = 0, r = st.size() - 1;
        while (l < r) {
            int mid = (l + r + 1) >> 1;
            if (st.get(mid)[1] < start) l = mid;
            else r = mid - 1;
        }
        return st.get(l)[2];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值