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
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
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] <= upper
cuá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 esnums[i1] >= nums[j]-upper
legal, 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:
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);
}
};