给定一个数查找所在区间或者查找所有重叠区间的算法总结
文章目录
- 区间操作相关的算法
- 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]
对于新的序列有这么两个特点:
- 偶数位是原区间的左端点,奇数位是原区间的右端点。
- 序列的长度为偶数。
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]
对于新的序列有这么两个特点:
- 偶数位是原区间的左端点,奇数位是原区间的右端点。
- 序列的长度为偶数。
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