当前位置: 首页 > article >正文

给定一个数查找所在区间或者查找所有重叠区间的算法总结

文章目录

  • 区间操作相关的算法
    • 1.前言
    • 2.算法
      • 2.1.查找区间算法
        • 2.1.2.流程图
      • 2.2.查找所有重叠区间的算法
        • 2.2.1.算法流程图
        • 2.2.2.代码实现
    • 3.测试

区间操作相关的算法

1.前言

在个人项目的研究中遇到一个和区间操作相关的场景,涉及到给定一个数,查找对应的区间和查找所有重叠的区间。现对这个问题的算法做个总结。

例1.给定若干个区间:

[1,3],[5,10],[21,26]

然后给定若干个数:0,1,2,3,8,26,29,查找这些数对应的区间,找不到就返回空。预期结果是

null
[1,3]
[1,3]
[1,3]
[5,10]
[21,26]
null

例2.给定若干个区间:

[1,3],[2,6],[10,29],[10,14],[22,78],[100,133]

找出以上区间中所有重叠的区间,找不到返回空。预期结果是

[1,3],[2,6]
[10,29],[10,14]
[10,29],[22,78]

2.算法

2.1.查找区间算法

可以借用二分查找的思想,首先可以在插入区间的时候按顺序插入。借用例1的数据,默认以区间左端点数值从小到大的顺序将区间插入,得到

a = [1,3,5,10,21,26]

对于新的序列有这么两个特点:

  1. 偶数位是原区间的左端点,奇数位是原区间的右端点。
  2. 序列的长度为偶数。
2.1.2.流程图

在这里插入图片描述

所以结合二分查找与序列的特点,就能在O(n) = log(n)的时间复杂度下找到对应区间。

2.1.3.代码实现

注:使用 c + + 20 \textcolor{BrickRed}{注:使用c++20} 注:使用c++20

auto find_segment(_Ty number)->std::optional<const IntervalNode<_Ty>>
{
    int l = 0;
    int h = m_segments.size() - 1;

    while (l <= h)
    {
        int m = (l + h) / 2;

        if (m & 1)
        {
            if (number >= m_segments[m - 1] && number <= m_segments[m])
            {
                return IntervalNode<_Ty>
                {
                    .left = m_segments[m - 1],
                    .right = m_segments[m]
                };
            }

            if (number < m_segments[m - 1]) h = m - 1;
            else if (number > m_segments[m]) l = m + 1;
        }
        else
        {
            if (number >= m_segments[m] && number <= m_segments[m + 1])
            {
                return IntervalNode<_Ty>
                {
                    .left = m_segments[m],
                    .right = m_segments[m + 1]
                };
            }

            if (number < m_segments[m]) h = m - 1;
            else if (number > m_segments[m + 1]) l = m + 1;
        }
    }

    return std::nullopt;
}

2.2.查找所有重叠区间的算法

借用前言中提到的例2中的数据,默认以区间左端点和右端点数值从小到大的顺序将区间插入,得到

a = [1,3,2,6,10,14,10,29,22,78,100,133]

对于新的序列有这么两个特点:

  1. 偶数位是原区间的左端点,奇数位是原区间的右端点。
  2. 序列的长度为偶数。
2.2.1.算法流程图

在这里插入图片描述

2.2.2.代码实现

注:使用 c + + 20 \textcolor{BrickRed}{注:使用c++20} 注:使用c++20

auto find_all_overlaps()->std::vector<std::tuple<const IntervalNode<_Ty>, const IntervalNode<_Ty>>>
{
    std::vector<std::tuple<const IntervalNode<_Ty>, const IntervalNode<_Ty>>> findOverlaps;

    for (int i = 0; i < m_segments.size() / 2 - 1; i++)
    {
        for (int j = i + 1; j < m_segments.size() / 2; j++)
        {
            if (m_segments[2 * i] <= m_segments[2 * j] && m_segments[2 * i + 1] >= m_segments[2 * j])
            {
                std::tuple<const IntervalNode<_Ty>, const IntervalNode<_Ty>> overlaps
                {
                    IntervalNode<_Ty>
                    {
                        .left = m_segments[2 * i],
                        .right = m_segments[2 * i + 1]
                    },
                    IntervalNode<_Ty>
                    {
                        .left = m_segments[2 * j],
                        .right = m_segments[2 * j + 1]
                    },
                };

                findOverlaps.push_back(overlaps);
            }
        }
    }

    return findOverlaps;
}

3.测试

class CCIntervalTester
{
public:
    auto TestFindSegment()->void
    {
        Algorithm::CCInterval<int> interval;

        interval.add_segment(1, 3);
        interval.add_segment(5,10);
        interval.add_segment(21,26);

        srand(time(NULL));

        for (int i = 0; i < 20; i++)
        {
            auto r = rand() % 30;
            const auto& f = interval.find_segment(r);
            if (f != std::nullopt)printf("%d in [%d,%d]\n", r, f.value().left, f.value().right);
            else printf("%d not found.\n",r);
        }
    }

    auto TestFindAllOverlaps()->void
    {
        Algorithm::CCInterval<int> interval;
        interval.add_segment(1, 3);
        interval.add_segment(2, 6);
        interval.add_segment(10, 29);
        interval.add_segment(10, 14);
        interval.add_segment(22, 78);
        interval.add_segment(100, 133);

        const auto& o = interval.find_all_overlaps();

        for (const auto& i : o)
        {
            printf(
                "[%d,%d] and [%d,%d]\n",
                std::get<0>(i).left, std::get<0>(i).right,
                std::get<1>(i).left, std::get<1>(i).right);
        }
    }
};

在这里插入图片描述

完整代码请移步至我的github:https://github.com/singlefreshBird/Algorithm


http://www.kler.cn/a/405188.html

相关文章:

  • OceanBase数据库产品与工具介绍
  • JVM(五、垃圾回收器)
  • C++标准模板库 -- map和set
  • 低速接口项目之串口Uart开发(二)——FIFO实现串口数据的收发回环测试
  • java Map 遍历 详解
  • PlncRNA-HDeep:使用基于两种编码风格的混合深度学习进行植物长非编码 RNA 预测
  • Mac配置maven环境及在IDEA中配置Maven
  • @Autowired 和 @Resource思考(注入redisTemplate时发现一些奇怪的现象)
  • 商用密码产品认证名录说明
  • C++在实际项目中的应用第二节:C++与区块链
  • oracle初始化参数
  • Flutter:AnimatedBuilder自定义显示动画
  • mac-mini的时间机器,数据备份到alist 中的网盘
  • 山东春季高考-C语言-综合应用题
  • WPF里面的C1FlexGrid表格控件添加RadioButton单选
  • Hive离线数仓结构分析
  • 树莓派2装FreeBSD14.1 Raspberry Pi2 install FreeBSD14.1 00000121:error:0A000086:SSL
  • ✅✅✅【Vue.js】sd.js基于jQuery Ajax最新原生完整版for凯哥API版本
  • 深度学习中的正则化技术
  • C++中的组合模式
  • 「Mac玩转仓颉内测版23」基础篇3 - 深入理解整数类型
  • Ubuntu24.04解决向日葵安装libgconf-2-4依赖问题
  • 鸿蒙学习高效开发与测试-ArkUI 框架(2)
  • MySQL 视图使用详解
  • [C#] 关于数组的详细解释以及使用注意点
  • 【QT常用技术讲解】QSettings把中文输入到配置文件