[LeetCode] 1395. Recuento Número de equipos

Hay  n soldados de pie en una línea. Cada soldado se le asigna un único  rating valor.

Usted tiene que formar un equipo de 3 soldados entre ellos bajo las siguientes reglas:

  • Elegir 3 soldados con índice ( ijk) con la calificación de ( rating[i]rating[j]rating[k]).
  • Un equipo es válida si: ( rating[i] < rating[j] < rating[k]) o ( rating[i] > rating[j] > rating[k]), donde ( 0 <= i < j < k < n).

Devuelve el número de equipos que pueden formar dadas las condiciones. (Soldados pueden ser parte de varios equipos).

 

Ejemplo 1:

Entrada: Valoración = [2,5,3,4,1] 
de salida: 3 
Explicación: Podemos formar tres equipos dadas las condiciones. (2,3,4), (5,4,1), (5,3,1).

Ejemplo 2:

Entrada: Valoración = [2,1,3] 
de salida: 0 
Explicación: No podemos formar cualquier equipo dadas las condiciones.

Ejemplo 3:

Entrada: Valoración = [1,2,3,4] 
de salida: 4

 

limitaciones:

  • n == rating.length
  • 1 <= n <= 200
  • 1 <= rating[i] <= 10^5

 

Las limitaciones de este problema permite una fuerza bruta O solución (N ^ 3) simplemente comprobando todos los tripletes posibles. Sin embargo, si se aumenta el tamaño de entrada de 10 ^ 5, estamos obligados a llegar a un algoritmo más eficiente para resolver este problema.

 

Primer punto debemos observar es que si podemos llegar a un algoritmo eficiente para la condición ( rating[i] < rating[j] < rating[k]), donde ( 0 <= i < j < k < n), entonces podemos simplemente invertir la matriz de entrada y aplicar el mismo algoritmo para la condición ( rating[i] > rating[j] > rating[k]), donde ( 0 <= i < j < k < n).

 

paseo Vamos a través del siguiente ejemplo para tener una idea de cómo un algoritmo eficiente debería funcionar: 

2 5 3 4 1 6

 

Si sólo tenemos en cuenta el caso en aumento, la respuesta es 5 muestra como la siguiente.

(2, 3, 4)

(2, 5, 6)

(2, 3, 6)

(2, 4, 6)

(3, 4, 6)

Let's find all triplets by traversing the input array and make each element V as the largest number of a valid triplet if possible. If we denote each element V's smaller preceeding number count as Cnt(V) and the number of valid triplets ending at V as Sum(V). Then we have the following formula:

Sum(V) = Cnt(1) + Cnt(2) + ..... + Cnt(V - 1).

 

In another word, in order to find the number of valid triplets ending in V, we need to sum the contributions from 1 to V - 1 as the middle number. The contribution of each number in [1, V - 1] equals to its count of smaller proceeding numbers. 

 

A walk through of provided example with this idea is:

i = 0,  a[i] = 2;      Sum(2) = 0; Cnt(2) = 0;

i = 1,  a[i] = 5;     2 < 5 but there isn't enough numbers to make an increasing triplet at this point. Sum(5) = 0; Cnt(5) = 1;

i = 2, a[i] = 3, T = 0;      2 < 3 but 2 has no smaller number ahead of it to use as the smallest number in a triplet. Sum(3) = 0; Cnt(3) = 1;

i = 3, a[i] = 4, T = 1;      3 has 1 smaller number 2 ahead of it. Sum(4) = Sum(1) + Sum(2) + Sum(3) = 1; Cnt(4) = 2;

i = 4, a[i] = 1, T = 0;      no number ahead of 1 is smaller. Sum(1) = 0; Cnt(1) = 0;

i = 5, a[i] = 6, T = 4;      5 has 2 ahead of it; 3 has 2 ahead of it; 4 has 2 and 3 ahead of it. Sum(6) = Sum(1) + Sum(2) + Sum(3) + Sum(4) + Sum(5) = 1 + 1 + 2 = 4.

All 1 to 5 can be used as the smallest number in a triplet with 6 being the middle number. Cnt(6) = 5.

The total count of increasing triplet is the total number of triplets that end on each element, which is 1 + 4 = 5.

 

To solve this problem efficiently, we need to achieve the following efficiently.

1. Get the total count of smaller proceeding numbers(as smallest numbers) of V's smaller proceeding numbers(as middle numbers) in order to get the count of triplets ending at V(as largest number). 

2. Update the total count of smaller proceeding numbers for V. This will be used later when V is used as a triplet middle number. This is a point update 

 

We also need to support the above operations dynamically as we scan the entire array one element at a time.  Binary Indexed Tree fits this purpose perfectly. We can use a BIT bit1 to achieve both operations in log(Max Rating) time. Operation 1 is a range sum query for all numbers' total count of smaller proceeding numbers. Operation 2 is a point update on a number's count of smaller proceeding numbers. To get the count of smaller proceeding numbers of a given number, we need a separate BIT bit2 to perform range query and point update. 

 

Essentially, bit1 supports querying/updating the total count of first number of tripets; bit2 supports querying/updating the total count of middle number of triplets. After considering each element V as the last number of a triplet, we then update its smaller proceeding number count in bit2 so V can be used later as a possible middle number in a triplet.

 

The runtime is O(N * log (Max Rating)). The max rating is 10^5 so index compression is not needed. If the max rating can go up to 10^7,  we need to apply the compression technique used in the related problem below.

 

 

class Solution {
    private class BinaryIndexedTree {
        int[] ft;
        BinaryIndexedTree(int n) {
            ft = new int[n + 1];
        }
        int rsq(int r) {
            int sum = 0;
            for(; r > 0; r -= (r & (-r))) {
                sum += ft[r];
            }
            return sum;
        }
        void update(int k, int v) {
            for(; k < ft.length; k += (k & (-k))) {
                ft[k] += v;
            }
        }
    }
    public int numTeams(int[] rating) {
        int cnt = 0;
        int maxR = 0;
        for(int r : rating) {
            maxR = Math.max(maxR, r);
        }
        cnt += solve(rating, maxR);
        reverse(rating);
        cnt += solve(rating, maxR);
        return cnt;
    }
    private int solve(int[] rating, int n) {
        BinaryIndexedTree bit1 = new BinaryIndexedTree(n);
        BinaryIndexedTree bit2 = new BinaryIndexedTree(n);
        
        int sum = 0;
        for(int i = 0; i < rating.length; i++) {
            sum += bit1.rsq(rating[i] - 1);
            bit1.update(rating[i], bit2.rsq(rating[i] - 1));
            bit2.update(rating[i], 1);
        }
        return sum;
    }
    private void reverse(int[] rating) {
        int i = 0, j = rating.length - 1;
        while(i < j) {
            int temp = rating[i];
            rating[i] = rating[j];
            rating[j] = temp;
            i++;
            j--;
        }
    }
}

 

 

 

 

 

Related Problem : Moving Points

 

Supongo que te gusta

Origin www.cnblogs.com/lz87/p/12602969.html
Recomendado
Clasificación