Cómo contar la presencia de un conjunto de números en un conjunto de intervalos de manera eficiente

STEALTHBOMBER90:

Los parámetros de entrada son una lista de tuplas que representan los intervalos y una lista de números enteros. El objetivo es escribir una función que cuenta el número de intervalos cada entero está presente en y devolver este resultado como una matriz asociativa. Así por ejemplo:

Input intervals: [(1, 3), (5, 6), (6, 9)]
Input integers: [2, 4, 6, 8]
Output: {2: 1, 4: 0, 6: 2, 8: 1}

Otro ejemplo:

Input intervals: [(3, 3), (22, 30), (17, 29), (7, 12), (12, 34), (18, 38), (30, 40), (5, 27), (19, 26), (27, 27), (1, 31), (17, 17), (22, 25), (6, 14), (5, 7), (9, 19), (24, 28), (19, 40), (9, 36), (2, 32)]
Input numbers: [16, 18, 39, 40, 27, 28, 4, 23, 15, 24, 2, 6, 32, 17, 21, 29, 31, 7, 20, 10]
Output: {2: 2, 4: 2, 6: 5, 7: 6, 10: 7, 15: 6, 16: 6, 17: 8, 18: 8, 20: 9, 21: 9, 23: 11, 24: 12, 27: 11, 28: 9, 29: 8, 31: 7, 32: 6, 39: 2, 40: 2}

¿Cómo hago para escribir una función que hace esto de manera eficiente? Ya tengo la implementación O (nm) con n el número de intervalos y M el número de enteros pero yo estoy buscando algo más eficiente.

Lo que tengo en este momento:

def intervals_per_number(numbers, intervals):
    result_map = {i: 0 for i in numbers}
    for i in result_map.keys():
        for k in intervals:
            if k[0] <= i <= k[1]:
                result_map[i] += 1
    return result_map

Esperanza he explicado lo suficientemente bien. Déjame saber si algo aún no está claro.

Gracias por adelantado.

Paul Hankin:

Poner sus números enteros, los puntos de inicio y fin a puntos en una sola lista de pares. Hacer que el primer elemento de cada par el valor del número entero, punto o punto extremo de inicio, y el segundo elemento de cada par sea 0, -1, o 1, dependiendo de si se trata de un número entero, punto o punto final de empezar.

A continuación, ordenar la lista.

Ahora, usted puede ir a través de la lista, el mantenimiento de una suma continua de los segundos elementos de los pares. Cuando vea un par de segundos el elemento 0, registrar la suma continua (negado) para ese número entero.

Este tiempo se ejecuta en O ((N + M) log (N + M)) en el peor de los casos (y en la práctica que supongo que va a ser lineal si las consultas y los intervalos son en su mayoría ordenados, gracias a timsort).

Por ejemplo:

Input intervals: [(1, 3), (5, 6), (6, 9)]
Input integers: [2, 4, 6, 8]

Unified list (sorted):
[(1,-1), (2,0), (3,1), (4,0), (5,-1), (6, -1), (6,0), (6,1), (8,0), (9,1)]

Running sum:
[-1    , -1,    0,     0,      -1,    -2,      0,      -1,    -1,   0]

Values for integers:
2: 1, 4: 0, 6: 2, 8, 1

Código de ejemplo:

def query(qs, intervals):
    xs = [(q, 0) for q in qs] + [(x, -1) for x, _ in intervals] + [(x, 1) for _, x in intervals]
    S, r = 0, dict()
    for v, s in sorted(xs):
        if s == 0:
            r[v] = S
        S -= s
    return r

intervals = [(3, 3), (22, 30), (17, 29), (7, 12), (12, 34), (18, 38), (30, 40), (5, 27), (19, 26), (27, 27), (1, 31), (17, 17), (22, 25), (6, 14), (5, 7), (9, 19), (24, 28), (19, 40), (9, 36), (2, 32)]
queries = [16, 18, 39, 40, 27, 28, 4, 23, 15, 24, 2, 6, 32, 17, 21, 29, 31, 7, 20, 10]
print(query(queries, intervals))

Salida:

{2: 2, 4: 2, 6: 5, 7: 6, 10: 7, 15: 6, 16: 6, 17: 8, 18: 8, 20: 9, 21: 9, 23: 11, 24: 12, 27: 11, 28: 9, 29: 8, 31: 7, 32: 6, 39: 2, 40: 2}

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=298573&siteId=1
Recomendado
Clasificación