LeetCode: 327. El número de sumas de intervalos en orden inverso / multiset / búsqueda binaria + inserción binaria

Dado un número entero de matrices, devuelve el intervalo y el número entre [inferior, superior], incluyendo inferior y superior.
El intervalo y S (i, j) representan la suma de los elementos en la posición de i a j en números, incluidos i y j (i ≤ j).

Nota: La
complejidad del algoritmo más intuitiva es O (n2), optimice su algoritmo sobre esta base.

Ejemplo:
Entrada: nums = [-2,5, -1], inferior = -2, superior = 2,
Salida: 3
Explicación: Los tres intervalos son: [0,0], [2,2], [0 , 2], y sus sumas son: -2, -1, 2.

Fuente: LeetCode Enlace: https://leetcode-cn.com/problems/count-of-range-sum El
copyright pertenece a la red de deducción. Comuníquese con la autorización oficial para la reimpresión comercial e indique la fuente de la reimpresión no comercial.

Ideas

Búsqueda / inserción binaria

Mantenemos una matriz ordenada que representa la suma de intervalo conocida actual, y luego cada vez que avanzamos el punto final derecho, obtenemos una nueva suma de prefijo, porque la suma de intervalo es sum[r] - sum[l-1], el objetivo se convierte en:

  • Conociendo el prefijo del punto final derecho y sr del intervalo actual, encuentre todos los puntos finales izquierdos sl para que satisfagan lower<= sr - sl <=upper

Luego hay un rango de sl: [sr-upper, sr-lower]
en una matriz conocida que almacena valores sl en orden ascendente, búsqueda binaria:
encuentre el primer i tal que sl sea mayor o igual que sr-upper
encuentre el primer j tal que sl sea mayor que sr-
ji es el sr actual Punto final derecho) puede estar compuesto por el número de pares en orden inverso

Luego agregue sr a la matriz sl (la posición de inserción también debe buscarse mediante búsqueda binaria), listo para prepararse para el siguiente sr

Perdón por no ser
Inserte la descripción de la imagen aquí

class Solution {
public:
    int countRangeSum(vector<int>& nums, int lower, int upper)
    {
        vector<long long> sumArr{0};
        long long ans=0, sum=0;
        for(int i=0; i<nums.size(); i++)
        {
            sum += nums[i];
            auto l = lower_bound(sumArr.begin(), sumArr.end(), sum-upper);
            auto r = upper_bound(sumArr.begin(), sumArr.end(), sum-lower);
            ans += r-l;
            auto x = lower_bound(sumArr.begin(), sumArr.end(), sum);
            sumArr.insert(x, sum);
        }
        return (int)ans;
    }
};

Introducir optimización multiset para evitar la degradación

Debido a que se mantiene la matriz de búsqueda binaria en el peor de los casos, la búsqueda puede degenerar en O (n) en lugar de O estable (log (n)). Para mantener O estable (log (n)) , necesitamos usar ** rojo Black Tree (multiset) ** reemplaza la matriz ordenada anterior y realiza una búsqueda binaria

Finalmente AC
Inserte la descripción de la imagen aquí

class Solution {
public:
    int countRangeSum(vector<int>& nums, int lower, int upper)
    {
        multiset<long long> sumSet{0};
        long long ans=0, sum=0;
        for(int i=0; i<nums.size(); i++)
        {
            sum += nums[i];
            auto l = sumSet.lower_bound(sum-upper);
            auto r = sumSet.upper_bound(sum-lower);
            ans += distance(l, r);
            sumSet.insert(sum);
        }
        return (int)ans;
    }
};

Solución positiva: par inverso

De hecho, en los números de prefijo y matriz, encuentre i, j tal que i <j y lower<= nums[j] - nums[i] <= uppercuántos pares están satisfechos . Si observa de cerca, es un poco como [ problema de par de orden inverso ]. Este tipo de encontrar un par de números cumple un cierto tamaño. Relación (A [i] + sesgo <o> A [j])

Determine la relación de tamaño
, es decir, encuentre nums [i] para satisfacernums[j]-upper <= nums[i] <= nums[j]-lower

Desmontaje pregunta es:
find nums [i1] hace nums[j]-upper <= nums[i1]
buscan marcas nums [I2]nums[i2] <= nums[j]-lower

El problema se traduce en:
si la matriz se divide en dos mitades, cada mitad está en orden ascendente (después de la fusión y la llamada recursiva), determinada a la izquierdai1, i2

  • Encuentre el primer i1 tal que nums[i1] < nums[j]-upper(debido al incremento, el lado derecho de i1 es nums[i1] >= nums[j]-upperlegal, y tanto i1 como su izquierda son ilegales)
  • Encuentre el primer i2 tal que nums[i2] <= nums[j]-lower(i2 y su izquierda son legales)

i2-i1 es la respuesta para cumplir con los dos límites, como se muestra en la figura:
Inserte la descripción de la imagen aquí

Tenga en cuenta que la
enumeración j está indexada de grande a pequeña, ya que debe estar en orden ascendente nums[i]< nums[j]. Si la enumeración j es de pequeña a grande, porque no retrocede , entonces nums [j] se hace más grande, lo que puede hacer que la i anterior se repita. Algunos números [i] están disponibles.

class Solution {
public:
    int mer(vector<long long>& nums, int l, int r, int lower, int upper)
    {
        if(l>=r || l<0 || r>=nums.size()) return 0;
        int mid=(l+r)/2, cnt=0, i1=mid, i2=mid;
        cnt += mer(nums, l, mid, lower, upper)+mer(nums, mid+1, r, lower, upper);
        for(int j=r; j>mid; j--)
        {
            while(i1>=l && nums[i1]>=nums[j]-upper) i1--;
            while(i2>=l && nums[i2]>nums[j]-lower) i2--;
            cnt += i2-i1;
        }
        inplace_merge(nums.begin()+l, nums.begin()+mid+1, nums.begin()+r+1);
        return cnt;
    }
    int countRangeSum(vector<int>& nums, int lower, int upper)
    {
        vector<long long> NUMS(nums.size()+1); NUMS[0]=0;
        for(int i=0; i<nums.size(); i++)
            NUMS[i+1]=nums[i]+NUMS[i];
        return mer(NUMS, 0, NUMS.size()-1, lower, upper);
    }
};
262 artículos originales publicados · ganó 11 · 10 mil visitas

Supongo que te gusta

Origin blog.csdn.net/weixin_44176696/article/details/105092920
Recomendado
Clasificación