【Leetcode】757. Set Intersection Size At Least Two(配数学证明)

题目地址:

https://leetcode.com/problems/set-intersection-size-at-least-two/

给定 n n n个闭区间,形如 [ a , b ] [a,b] [a,b],其中 a < b a<b a<b且都为非负整数,这些区间只含整数。要求选若干点,使得每个区间都含那些点中的至少两个点。问至少要选多少个点。

思路是贪心。先按右端点从小到大排序,直觉上每次选最右边的两个点能覆盖住最多的区间。算法如下:
1、开两个变量 x , y x,y x,y x < y x<y x<y,表示当前选择的最右边的两个点的位置,初始化为 − 1 -1 1(因为所有区间都不含负数);
2、遍历区间,如果当前区间 A A A左端点大于 y y y,那么必须新选两个点了,选该区间的右端点 A [ 1 ] A[1] A[1] A [ 1 ] − 1 A[1]-1 A[1]1这两个点;
3、如果当前区间 A [ 0 ] = y A[0]=y A[0]=y,那么只需要多选一个点 A [ 1 ] A[1] A[1]即可;
4、如果 x < A [ 0 ] < y x<A[0]<y x<A[0]<y,也是只需要多选一个点,但是要看一下 A [ 1 ] A[1] A[1],如果 A [ 1 ] = y A[1]=y A[1]=y的话,那么选 A [ 1 ] − 1 A[1]-1 A[1]1,否则选 A [ 1 ] A[1] A[1]
5、遍历的同时对选了多少个点计数。

算法正确性证明:
首先贪心解确实能覆盖所有区间,所以贪心解选的点数大于等于最优解。如果某个最优解不是贪心解,找到贪心解里选了但是最优解里没选的点:
1、上面的 2 2 2,对于某个区间,其左端点大于了其左边所有区间的右端点,因为贪心解会选这个区间的最右边两个点,所以最优解必然不是选的这两个点,那么可以调整过去,最优解的那两个点可以覆盖的区间,贪心解的那两个点也能覆盖,所以调整后仍然是最优解;
2、上面的 3 3 3 4 4 4可以类似证明。

代码如下:

import java.util.Arrays;

public class Solution {
    public int intersectionSizeTwo(int[][] intervals) {
        Arrays.sort(intervals, (i1, i2) -> Integer.compare(i1[1], i2[1]));
        // last2 < last1
        int res = 0, last1 = -1, last2 = -1;
        for (int[] interval : intervals) {
            if (interval[0] > last1) {
                last2 = interval[1] - 1;
                last1 = interval[1];
                res += 2;
            } else if (interval[0] == last1 || interval[0] > last2) {
                if (interval[1] > last1) {
                    last2 = last1;
                    last1 = interval[1];
                } else {
                    last2 = last1 - 1;
                }
                
                res++;
            }
        }
        
        return res;
    }
}

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn),空间 O ( 1 ) O(1) O(1)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值