LeetCode 757. Set Intersection Size At Least Two

本文介绍了LeetCode 757题目的解题思路,包括问题定义、分析和具体实现。通过排序区间并按特定策略添加元素到集合中,保证与每个区间至少有2个交集元素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、题目描述

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].

 


 

二、题目分析

  依题意,我们需要求出一个 最小 集合 S ,使得 S 中至少有两个数落在 intervals 中给出的每个闭区间中,即 Sintervals 中给出的每个闭区间的交集的元素个数大于等于 2。最后返回该集合 S 的元素个数。

  这里我们可以考虑从“最初”开始构建这样的一个集合。将 intervals 中的区间按照右端点的升序进行排序,若右端点相等,则以左端点的降序进行排序(原因说明在之后)。将排序后的一个区间的最后两个整数首先加入 S 中,作为“最初”的情况,之后再遍历处理剩下的区间。
  在遍历到某一个区间 I 时,此时的 S 应能满足排在该区间之前的所有区间,在这样的前提下我们来处理这个区间 I。简单来看,只需判断 ∣I∩S∣| I∩S |IS 的大小即可。

  • 若等于 2,则说明可以满足条件,无需再添加数字到 S 中。
  • 若等于 1,则我们还需要从 I 中选择一个整数添加到 S 中,使得它们交集的元素个数大于2,那么显然,我们选择 I 中的最后一个整数,这也是我们按右端点升序排序的原因——这既能使得 ∣I∩S∣=2| I∩S | = 2IS=2,也能尽量地去满足之后的区间,并且 S 应是最小的( S 中的数字也会按升序排序)。
  • 若等于 0,则需要添加两个整数,那么我们同样选择 I 中最后的数字,但此时应是最后的两个整数,理由同上。

  剩下的问题就是 ∣I∩S∣| I∩S |IS 的大小了,要求交集的元素个数,又是一个痛苦的遍历过程。但在这里一个更简单的方式是,只维护 S 的最后两个元素 lastButOnelast。此时我们只需要判断 I 的第一个整数I[0]和这两个数字的大小关系即可。

  • I[0] <= lastButOne ,即小于等于 S 中倒数第二个数,那么 ∣I∩S∣| I∩S |IS 应为 2,S 不会被更新。显然,此时 I 会包含这两个数(因为按右端点降序排序,I 的右端点肯定会大于等于这两个包含在之前的区间中的数)。
  • I[0] > lastButOne && I[0] <= last ,那么 ∣I∩S∣| I∩S |IS 应为 1。此时 last 应含于 I 。我们也要加入 I 的最后一个整数到 S 中,相应地更新 lastlastButOne 的值。
  • I[0] > last,那么 ∣I∩S∣| I∩S |IS 显然应为 0。此时加入 I 的最后两个整数到 S 中,相应地更新 lastlastButOne 的值。

  而当右端点相等就按照左端点降序排序则是因为,这里 S 中加入的数越多,其优先度就越大,即应该更早地做(并不会影响最终结果),所以我们要使 I[0] 尽可能大,这样 I[0] 才更有机会大于 last(这其实也避免了 last == lastButOne 的情况)。

  以这种方式,我们就只需做简单的判断而避免了求交集的情况,也不用维护实际的集合 S ,大大简化了过程。

 


 

三、具体实现

  按照以上分析,总体复杂度应为 O(NlogN)O(NlogN)O(NlogN),即排序的复杂度。

class Solution
{
  public:
    int intersectionSizeTwo( vector<vector<int>> &intervals )
    {
        sort( intervals.begin(), intervals.end(), 
            []( const vector<int> &v1, const vector<int> &v2 ) 
            { return v1.back() == v2.back() ? v1.front() > v2.front() : v1.back() < v2.back(); } );

        int setSize = 2;
        int last = intervals.front().back(), lastButOne = last - 1;

        for ( size_t i = 1; i < intervals.size(); ++i ) {

            if ( intervals.at( i ).front() > lastButOne ) {

                if ( intervals.at( i ).front() <= last ) {
                    ++setSize;
                    lastButOne = last;
                } else {
                    setSize += 2;
                    lastButOne = intervals.at( i ).back() - 1;
                }
                last = intervals.at( i ).back();

            }

        }

        return setSize;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值