757. Set Intersection Size At Least Two

 

An integer interval [a, b] (for integers a < b) is a set of all consecutive integers from a to b, including a and b.

Find the minimum size of a set S such that for every integer interval A in intervals, the intersection of S with A has size at least 2.

Example 1:

Input: intervals = [[1, 3], [1, 4], [2, 5], [3, 5]]
Output: 3
Explanation:
Consider the set S = {2, 3, 4}.  For each interval, there are at least 2 elements from S in the interval.
Also, there isn't a smaller size set that fulfills the above condition.
Thus, we output the size of this set, which is 3.

 

Example 2:

Input: intervals = [[1, 2], [2, 3], [2, 4], [4, 5]]
Output: 5
Explanation:
An example of a minimum sized set is {1, 2, 3, 4, 5}.

 

Note:

  1. intervals will have length in range [1, 3000].
  2. intervals[i] will have length 2, representing some integer interval.
  3. intervals[i][j] will be an integer in [0, 10^8].

 

 

 

Approach #1: Greedy [Accepted]

 

Intuition

Let's try to solve a simpler problem: what is the answer when the set intersection size is at least one?

Sort the points. Take the last interval [s, e], which point on this interval will be in S? Since every other interval has start point <= s, it is strictly better to choose s as the start. So we can repeatedly take s in our set S and remove all intervals containing s.

We will try to extend this solution to the case when we want an intersection of size two.

Algorithm

For each interval, we will perform the algorithm described above, storing a todo multiplicity which starts at 2. As we identify points in S, we will subtract from these multiplicities as appropriate.

One case that is important to handle is the following: [[1, 2], [2, 3], [2, 4], [4, 5]]. If we put 4, 5 in S, then we put 2 in S, when handling [2, 3] we need to put 3 in S, not 2 which was already put.

We can handle this case succinctly by sorting intervals [s, e] by s ascending, then e descending. This makes it so that any interval encountered with the same s has the lowest possible e, and so it has the highest multiplicity. When at interval [s, e] and choosing points to be included into S, it will always be the case that the start of the interval (either s or s, s+1) will be unused.

 

思路:(1)按照start或者end来排序,(2)从排序的前面或者后面开始遍历

 

枚举讨论一下发现:可以按照start来排,然后从后面开始遍历;或者按照end来排,然后从前面开始遍历

对于K=2的情况,当然也是取最边上的2个数,但是因为可能已经有2个在某个区间了,这时候就需要判断要不要加上边上的数,加几个?可以有2中方法

(1)判断当前set里面有多少个数在当前interval里面

(2)每次加入一个数就更新每个interval还需要添加的个数

class Solution:
    def intersectionSizeTwo(self, intervals):
        """
        :type intervals: List[List[int]]
        :rtype: int
        """
        intervals.sort(key=lambda l: (l[0], -l[1]))  # tricky sort
        todo = [2]*len(intervals)  # how many need to add for intersect
        ret = 0
        
        while intervals:
            (s,e), t = intervals.pop(), todo.pop()  # list pop from end
            # greedy: add from start point s
            for p in range(s, s+t):
                ret += 1
                for i, (s0,e0) in enumerate(intervals):
                    if todo[i] and p<=e0:  # since sorted, p is always > e0
                        todo[i] -= 1
        return ret
    
s=Solution()
print(s.intersectionSizeTwo([[1, 3], [1, 4], [2, 5], [3, 5]]))
print(s.intersectionSizeTwo([[1, 2], [2, 3], [2, 4], [4, 5]]))

查找二分优化为logN

其实排序完就只需要O(N),因为只需要维护最后加入的2个数,就可以判断当前interval满不满足条件

class Solution {
public:
    int intersectionSizeTwo(vector<vector<int>>& intervals) {
        sort(intervals.begin(), intervals.end(), [](vector<int>& a, vector<int>& b) {
            return a[1] < b[1] || (a[1] == b[1] && a[0] > b[0]); 
        });
        int n = intervals.size(), ans = 0, p1 = -1, p2 = -1;
        for (int i = 0; i < n; i++) {
            // current p1, p2 works for intervals[i]
            if (intervals[i][0] <= p1) continue;
            // Neither of p1, p2 works for intervals[i]
            // replace p1, p2 by ending numbers
            if (intervals[i][0] > p2) {
                ans += 2;
                p2 = intervals[i][1];
                p1 = p2-1;
            }
            // only p2 works;  
            else {
                ans++;
                p1 = p2;
                p2 = intervals[i][1];
            }
        }
        return ans;
    }
};

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值