【问题标题】:Check if a number exists in a given set of ranges检查给定范围内是否存在数字
【发布时间】:2014-12-05 11:11:29
【问题描述】:

假设我们有一组 N 个范围,(A1, B1) (A2, B2) (A3, B3) ... (An, Bn),其中 Ai 表示起点,Bi 表示终点范围。 (Ai、Bi为正整数)

我们如何使用二分搜索检查给定的整数,比如 X,是否存在于 N 个范围中的至少一个范围内?

我的做法:

  1. 先按 x 坐标再按 y 坐标对范围进行排序。

  2. 找到大于或等于 X 的最小 x 坐标。

  3. 检查是否满足该范围。

  4. 如果是,我们有解决方案。

现在,如果该范围不包含 X,我的下一步应该是什么?

或者,解决方案应该完全不同吗?

【问题讨论】:

  • 您需要对数据进行预处理,使范围不相交(通过合并重叠范围)并进行排序。你可以做到这一点是 O(n log n) 时间。然后可以使用二分搜索来测试一个点是否在至少一个范围内。

标签: algorithm sorting binary-search


【解决方案1】:

首先,如果范围没有排序,你最好逐个检查而不是进行任何花哨的二进制搜索,因为检查每个范围最多为 O(n),而排序然后二进制搜索时间至少为 O(n log n)。

无论如何,在这种情况下,我会将具有相同 x 坐标的所有范围视为单个节点,因此当您进行二进制搜索时,您获得的中间节点实际上是具有相同 x 坐标的范围组相同的 x 坐标。然后,您将检查该节点中最后一个范围的 y 坐标。如果数字不在这两者之间,则该数字不包含在该 节点 的任何范围内,因此您应该根据数字是高于还是低于x 或 y 坐标。

这是一个完整的 Python 工作示例:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import random
import itertools

MAX = 50
NUM_RANGES = 30

THE_NUMBER = random.randint(0, MAX)

ranges = []
# Generate random ranges
for e in range(NUM_RANGES):
    x = random.randint(0, MAX - 1)
    y = random.randint(x + 1, MAX)

    ranges.append((x,y))

# Group the ranges by starting coordinate
grouped_ranges = {x: [e for e in ranges if e[0] == x] for x in (e[0] for e in ranges)}

## Binary search
gkeys = grouped_ranges.keys()
gkeys_range = [0, len(gkeys)]

get_mid_key = lambda: (gkeys_range[1] + gkeys_range[0])/2
get_mid = lambda: grouped_ranges[gkeys[get_mid_key()]]

print "THE NUMBER:", THE_NUMBER
print "THE RANGES:", grouped_ranges

while 1:
    # Get middle element
    mid = get_mid()

    print gkeys_range

    old_range = gkeys_range[:]

    if THE_NUMBER < mid[0][0]:
        gkeys_range[1] = get_mid_key()
    elif THE_NUMBER > mid[-1][1]:
        gkeys_range[0] = get_mid_key()
    else:
        print "In this range:", mid
        break

    if gkeys_range == old_range:
        print "Not in any range"
        break

【讨论】:

  • 在进行二分搜索之前是否需要先对 grouped_ranges 进行排序?
【解决方案2】:

我从你的问题描述中得到的是你有pairs 就像(a1,b1) , (a2,b2)。其中ax 是范围的开始,bx 是结束。现在给你一个数字n,你想搜索这个数字是否在任何范围内。
先排序,然后合并重叠范围,然后应用二分查找:

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
    vector < pair <int , int> > b;
    b.push_back(make_pair(5,10));
    b.push_back(make_pair(75,100));
    b.push_back(make_pair(33,67));
    b.push_back(make_pair(9,21));
    b.push_back(make_pair(28,67));
    int m = b.size();
    sort(b.begin(), b.end());
    int j = 0;
    for (int i = 1; i < m; i++) {
        if (b[i].first <= b[j].second) {
            if (b[i].second > b[j].second) {
                b[j].second = b[i].second;
            }
        } 
        else {
            j++;
            b[j] = b[i];
        }
    }
    m = j + 1;
    for(int i = 0; i< m;i ++) {
        cout << b[i].first << " " << b[i].second << endl;
    }
    // Apply binary search now
    return 0;
}

我希望这能解决您的问题。我把二分搜索部分留给你作为练习。

【讨论】:

    猜你喜欢
    • 2017-05-16
    • 2021-03-15
    • 1970-01-01
    • 2015-11-28
    • 2017-05-28
    • 1970-01-01
    • 2021-04-01
    • 2014-05-05
    • 2010-11-01
    相关资源
    最近更新 更多