El algoritmo codicioso más comprensible.

1. Explicación del algoritmo

Como su nombre lo indica, el algoritmo codicioso o pensamiento codicioso adopta una estrategia codiciosa para garantizar que cada operación sea localmente óptima, de modo que el resultado final sea globalmente óptimo.


Para dar un ejemplo simple: a Xiao Ming y Xiao Wang les gusta comer manzanas, Xiao Ming puede comer cinco manzanas y Xiao Wang puede comer tres manzanas. Se sabe que hay infinitas manzanas en el huerto de manzanos, pregúntales a Xiao Ming y Xiao Wang cuántas manzanas pueden comer como máximo.


En este ejemplo, la estrategia codiciosa que podemos elegir es que cada persona coma la cantidad máxima de manzanas que pueda comer, que es localmente óptima para cada persona. Y debido a que el resultado global es una simple suma de resultados locales, y los resultados locales son irrelevantes entre sí, la estrategia local óptima es también la estrategia global óptima.


2. Problema de distribución

2.1 Distribución de cookies

2.1.1, descripción del tema

455. Repartir galletas

Digamos que eres un gran padre y quieres darles a tus hijos algunas galletas pequeñas. Sin embargo, a cada niño no se le da más de una galleta.

Para cada niño i, existe un valor de apetito g[i], que es el tamaño más pequeño de galleta que puede satisfacer el apetito del niño; y cada galleta jtiene un tamaño s[j]. Si s[j] >= g[i]podemos jdistribuir esta cookie a un niño i, el niño quedará satisfecho. Su objetivo es satisfacer a tantos niños como sea posible y generar este valor máximo.

2.1.2 Ejemplo de entrada y salida

Ejemplo 1:
Entrada: g = [1, 2, 3], s = [1, 1]
Salida: 1
Explicación:
Tiene tres hijos y dos galletas, y los valores de apetito de los tres niños son: 1, 2 , 3.
Aunque tienes dos galletas pequeñas, dado que ambas tienen un tamaño de 1, sólo puedes satisfacer a un niño con un valor de apetito de 1.
Entonces deberías generar 1.

Ejemplo 2:
Entrada: g = [1, 2], s = [1, 2, 3]
Salida: 2
Explicación:
Tiene dos hijos y tres galletas, y los valores de apetito de los dos niños son 1 y 2 respectivamente .
Tienes suficientes galletas tanto en cantidad como en tamaño para mantener satisfechos a todos los niños.
Entonces deberías generar 2.

2.1.3 Solución

Dado que el niño que tiene menos hambre tiene más probabilidades de sentirse satisfecho, lo consideramos primero. Para que las galletas restantes satisfagan al máximo el hambre del niño, debemos darle la galleta del tamaño más pequeño que sea mayor o igual al hambre del niño. Después de satisfacer a este niño, adoptamos la misma estrategia y consideramos al niño con menos hambre entre los niños restantes hasta que no haya galletas que satisfagan.


En resumen, la estrategia codiciosa aquí es asignar la galleta llena más pequeña al niño con menos hambre entre los niños restantes. En cuanto a la implementación específica, debido a que necesitamos obtener la relación de tamaño, una forma conveniente es ordenar los elementos secundarios y las cookies por separado. De esta forma, podemos partir del niño con menor hambre y de la galleta de menor tamaño, y calcular cuántos pares pueden satisfacer la condición.

class Solution {
    
    
    public int findContentChildren(int[] g, int[] s) {
    
    
        Arrays.sort(g);
        Arrays.sort(s);
        int child = 0, cookie = 0;
        // 优先给最小饥饿度的孩子分配最小的饼干
        while (child < g.length && cookie < s.length) {
    
    
            if (g[child] <= s[cookie]) {
    
    
                child++;
            }
            cookie++;
        }
        return child;
    }
}

Análisis de complejidad

  • Complejidad del tiempo: O(mlogm+nlogn) , donde myn son las longitudes de las matrices g y s, respectivamente. La complejidad temporal de ordenar dos matrices es O (mlogm + nlogn), y la complejidad temporal de atravesar las matrices es O (m + n), por lo que la complejidad temporal total es O (mlogm + nlogn).
  • Complejidad espacial: O(logm+logn) , donde myn son las longitudes de las matrices g y s, respectivamente. La complejidad del espacio es principalmente la sobrecarga de espacio adicional de la clasificación.

2.2 Distribución de caramelos

2.2.1, descripción del tema

135. Distribuyendo dulces

n Los niños se paran en fila. Se le proporciona una serie de números enteros ratingsque representan la calificación de cada niño.

Debes distribuir dulces a estos niños de acuerdo con los siguientes requisitos:

  • A cada niño se le asignan al menos 1dulces.
  • El niño con la puntuación más alta de dos niños adyacentes recibe más dulces.

Distribuya dulces a cada niño, calcule y devuelva la cantidad mínima de dulces que deben prepararse .

2.2.2 Ejemplo de entrada y salida

Ejemplo 1:
Entrada: calificaciones = [1, 0, 2]
Salida: 5
Explicación: Puede distribuir 2, 1 y 2 dulces al primer, segundo y tercer niño, respectivamente.

Ejemplo 2:
Entrada: calificaciones = [1, 2, 2]
Salida: 4
Explicación: Puede distribuir 1, 2 y 1 caramelo al primer, segundo y tercer niño respectivamente.
    El tercer niño solo recibe 1 caramelo, que cumple las dos condiciones del título.

2.2.3 Solución

Después de terminar 2.1、分发饼干el tema, ¿crees que se deben ordenar o seleccionar estrategias codiciosas con relaciones comparativas? Aunque esta pregunta también utiliza una estrategia codiciosa, solo necesitamos dos recorridos simples: inicializar el número de dulces de todos los niños a 1; atravesar primero de izquierda a derecha, si el niño de la derecha tiene una puntuación más alta que el niño de la izquierda. , luego el número de caramelos del niño de la derecha se actualiza al número de caramelos del niño de la izquierda más 1; luego recorre de derecha a izquierda, si la puntuación del niño de la izquierda es mayor que la del derecho, y el número actual de dulces del niño de la izquierda no es mayor que el número de dulces del niño de la derecha, entonces el número de dulces del niño izquierdo se actualiza al número de dulces del niño de la derecha más 1. A través de estos dos recorridos, los dulces asignados pueden cumplir con los requisitos del tema. La estrategia codiciosa aquí es que en cada recorrido, solo se considera y actualiza la relación de tamaño en el lado adyacente.


Por 示例1ejemplo, inicializamos la distribución de dulces como [1,1,1], el resultado después de la primera actualización transversal es [1,1,2] y el resultado después de la segunda actualización transversal es [2,1,2].

class Solution {
    
    
    public int candy(int[] ratings) {
    
    
        // 每个孩子至少一颗糖果
        int candyCount = ratings.length;
        // 用于记录每个孩子需要评分需要额外奖励的糖果数量
        int[] candyArr = new int[ratings.length];
        
        // 从左往右遍历一遍,如果右边孩子的评分比左边的高,则右边孩子的糖果数更新为左边孩子的糖果数加 1
        for (int i = 1; i < ratings.length; i++) {
    
    
            if (ratings[i] > ratings[i - 1]) {
    
    
                candyArr[i] = candyArr[i - 1] + 1;
                candyCount += candyArr[i];
            }
        }
        
        /*
         * 从右往左遍历一遍,如果左边孩子的评分比右边的高,
         * 且左边孩子当前的糖果数不大于右边孩子的糖果数(排除上面从左往右遍历过程中已追加的糖果数量影响),
         * 则左边孩子的糖果数更新为右边孩子的糖果数加 1
         */
        for (int i = ratings.length - 2; i >= 0; i--) {
    
    
            if (ratings[i] > ratings[i + 1] && candyArr[i] <= candyArr[i + 1]) {
    
    
                // 因该位置孩子的糖果数量较上次遍历又发生了变化,会导致重复计算,故需减去之前的数量,重新计算
                candyCount -= candyArr[i];
                candyArr[i] = candyArr[i + 1] + 1;
                candyCount += candyArr[i];
            }
        }
        return candyCount;
    }
}

Análisis de complejidad

  • Complejidad del tiempo: O(n) , donde n es el número de hijos. Necesitamos recorrer la matriz dos veces para calcular la cantidad mínima de caramelos que satisfacen el recorrido de izquierda a derecha y el recorrido de derecha a izquierda respectivamente.
  • Complejidad espacial: O(n) , donde n es el número de hijos. Necesitamos guardar la cantidad de dulces otorgados a cada niño durante los dos recorridos.

3. Problema de intervalo

3.1 No hay intervalos superpuestos

3.1.1, descripción del tema

435. Intervalos no superpuestos

Dada una colección de intervalos intervals, donde intervals[i] = [starti, endi]. Devuelve el número mínimo de intervalos que deben eliminarse para que los intervalos restantes no se superpongan.

3.1.2 Ejemplo de entrada y salida

Ejemplo 1:
Entrada: intervalos = [ [1, 2], [2, 3], [3, 4], [1, 3] ] Salida:
1 Explicación
: Después de eliminar [1,3], el intervalo restante existe sin superposición.

Ejemplo 2:
Entrada: intervalos = [ [1, 2], [1, 2], [1, 2] ]
Salida: 2
Explicación: Debe eliminar dos [1,2] para que los intervalos restantes no se superpongan.

Ejemplo 3:
Entrada: intervalos = [ [1, 2], [2, 3] ]
Salida: 0
Explicación: No es necesario eliminar ningún intervalo porque ya no se superponen.

3.1.3, solución del problema

El final del intervalo es muy importante a la hora de elegir el intervalo a conservar: cuanto más pequeño sea el final del intervalo seleccionado, más espacio quedará para otros intervalos y más intervalos se podrán conservar. Por tanto, la estrategia codiciosa que adoptamos es dar prioridad a retener intervalos con finales pequeños y disjuntos.


El método de implementación específico es ordenar primero los intervalos en orden creciente según el tamaño del final, y cada vez seleccionar el intervalo con el extremo más pequeño y que no se superponga con el intervalo seleccionado previamente. Aquí se utiliza Lambda de Java para una clasificación personalizada.


En 示例1, la matriz ordenada es [[1,2], [2,3], [1,3], [3,4]]. De acuerdo con nuestra estrategia codiciosa, primero inicializamos en el intervalo [1,2]; luego [2,3] no se cruza con [1,2], luego mantenlo; porque [1,3] se cruza con [2,3] , omita el intervalo; dado que [3,4] no interseca a [2,3], se mantiene. Por tanto, el intervalo reservado final es [[1,2], [2,3], [3,4]].

class Solution {
    
    
    public int eraseOverlapIntervals(int[][] intervals) {
    
    
        if (intervals.length <= 0) {
    
    
            return 0;
        }
        // 将区间按照结尾的大小进行增序排序
        List<int[]> intervalList = Arrays.stream(intervals).sorted(Comparator.comparingInt(interval -> interval[1])).collect(Collectors.toList());
        int ans = 0;
        for (int preIndex = 0, i = 1; i < intervalList.size(); i++) {
    
    
            // 比较后一个区间开始是否在前一个区间内即可
            if (intervalList.get(i)[0] < intervalList.get(preIndex)[1]) {
    
    
                ans++;
                continue;
            }
            preIndex = i;
        }
        return ans;
    }
}

Análisis de complejidad

  • Complejidad del tiempo: O(nlogn) , donde n es el número de intervalos. Necesitamos tiempo O (nlogn) para ordenar todos los intervalos en orden ascendente según el punto final derecho y tiempo O (n) para recorrerlos. Dado que el primero es asintóticamente mayor que el segundo, la complejidad del tiempo total es O (nlogn).
  • Complejidad del espacio: O(logn) , que es el espacio de pila necesario para ordenar.

4. Practica

4.1 Dificultad Básica

4.1.1 El problema de plantar flores

4.1.1.1, descripción del tema

605. El problema de plantar flores

Supongamos que hay un parterre de flores muy largo y algunas parcelas están plantadas con flores, pero la otra parte no. Sin embargo, no se pueden plantar flores en parcelas adyacentes, competirán por el agua y ambas morirán.

Se le proporciona un macizo de flores de matriz entera para representar un macizo de flores, que se compone de varios 0 y 1, donde 0 significa que no se plantaron flores y 1 significa que sí se plantan flores. Hay otro número n, ¿se pueden plantar n flores sin romper las reglas de plantación? Devuelve verdadero si es así, falso si no.

4.1.1.2, ejemplo de entrada y salida

Ejemplo 1:
Entrada: macizo de flores = [1, 0, 0, 0, 1], n = 1
Salida: verdadero

Ejemplo 2:
Entrada: macizo de flores = [1, 0, 0, 0, 1], n = 2
Salida: falso

4.1.1.3, solución del problema

Desde un punto de vista codicioso, se deben plantar tantas flores como sea posible sin romper las reglas de plantación, y luego juzgar si el número máximo de flores que se pueden plantar es mayor o igual a n; cuántas flores se plantan, por lo que se puede optimizar en el bucle, cuando el número de flores que se pueden plantar haya llegado a n, se puede devolver directamente sin continuar calculando el resto de la matriz.

class Solution {
    
    
    public boolean canPlaceFlowers(int[] flowerbed, int n) {
    
    
        for (int i = 0; i < flowerbed.length && n > 0; i++) {
    
    
            if (flowerbed[i] == 0 && (i == 0 || flowerbed[i - 1] == 0)
                    && (i == flowerbed.length - 1 || flowerbed[i + 1] == 0)) {
    
    
                n--;
                flowerbed[i] = 1;
            }
        }
        return n == 0;
    }
}

Análisis de complejidad

  • Complejidad del tiempo: O(n) , donde n es la longitud del macizo de flores de la matriz. La matriz debe atravesarse una vez.
  • Complejidad espacial: O(1) . El espacio extra utilizado es constante.

4.1.2 Detona el globo con el menor número de flechas

4.1.2.1, descripción del tema

452. Explotar globos con un número mínimo de flechas

Hay globos esféricos adheridos a una pared representada por un plano XY. Los globos en la pared están registrados en una matriz de números enteros points, donde points[i] = [xstart, xend]representa globos con un diámetro horizontal entre xstarty . xendNo sabes la coordenada y exacta del globo.

Un arco y una flecha se pueden disparar perfectamente verticalmente desde diferentes puntos a lo largo del eje x. Dispara una flecha en la coordenada x, si hay un globo cuyo diámetro comienza y termina en las coordenadas xstart, xendy satisface xstart ≤ x ≤ xend, entonces el globo será detonado . No hay límite para la cantidad de arcos que se pueden disparar . Una vez que se dispara el arco y la flecha, puede avanzar indefinidamente.

Dada una matriz , devuelve el número mínimopoints de flechas que se deben disparar para hacer explotar todos los globos .

4.1.2.2, ejemplo de entrada y salida

Ejemplo 1:
Entrada: puntos = [ [10, 16], [2, 8], [1, 6], [7, 12] ] Salida: 2 Explicación:
El globo
se puede reventar con 2 flechas:
○ en x = Dispara flechas desde 6 lugares y rompe globos [2,8] y [1,6].
○ Dispara la flecha en x = 11 y rompe los globos [10,16] y [7,12].

Ejemplo 2:
Entrada: puntos = [ [1, 2], [3, 4], [5, 6], [7, 8] ] Salida: 4
Explicación :
Cada globo necesita disparar una flecha, un total de 4 son flecha necesaria.

Ejemplo 3:
Entrada: puntos = [ [1, 2], [2, 3], [3, 4], [4, 5] ] Salida: 2
Explicación :
El globo se puede reventar con 2 flechas:
○ en x = Dispara flechas en 2 ubicaciones, rompiendo los globos [1,2] y [2,3].
○ Dispara la flecha en x = 4 y rompe los globos [3,4] y [4,5].

4.1.2.3, solución del problema

Esta pregunta es 3.1、无重叠区间muy similar a y también adopta una estrategia codiciosa: primero ordene los intervalos en orden creciente según el tamaño del extremo, y luego verifique si el arco y la flecha que detonaron el globo se mueven hacia el límite más a la derecha y si se puede detonar el siguiente globo de intervalo.


El método de implementación específico es ordenar primero los intervalos en orden ascendente según el tamaño del final. Aquí, se utiliza Java Lambda para una clasificación personalizada. Luego, primero preestablezca un arco y una flecha para cada intervalo, luego atraviese todos los globos en el intervalo, considere mover el arco y la flecha que detonaron el globo hasta el límite más a la derecha del intervalo y verifique si se superpone con el globo en el siguiente intervalo. , que puede salvar un arco y una flecha.

class Solution {
    
    
    public int findMinArrowShots(int[][] points) {
    
    
        // 最多需要的弓箭数
        int ans = points.length;
        // 将区间按照结尾的大小进行增序排序
        List<int[]> pointList = Arrays.stream(points).sorted(Comparator.comparingInt(point -> point[1])).collect(Collectors.toList());
        int preIndex = 0;
        for (int i = 1; i < pointList.size(); i++) {
    
    
            // 比较后一个区间是否和前一个区间重叠,重叠则可节约一支弓箭
            if (pointList.get(i)[0] <= pointList.get(preIndex)[1]) {
    
    
                ans--;
                continue;
            }
            preIndex = i;
        }
        return ans;
    }
}

Análisis de complejidad

  • Complejidad del tiempo: O(nlogn) , donde n es la longitud de los puntos de la matriz. La complejidad temporal de la clasificación es O (nlogn), y la complejidad temporal de atravesar todos los globos y calcular la respuesta es O (n), que es asintóticamente menor que la anterior, por lo que puede ignorarse.
  • Complejidad del espacio: O(logn) , que es el espacio de pila necesario para ordenar.

4.1.3 Dividir intervalos de letras

4.1.3.1, descripción del tema

763. Dividir intervalos alfabéticos

Una cadena Sconsta de letras minúsculas. Necesitamos dividir esta cadena en tantos fragmentos como sea posible, y la misma letra aparece como máximo en un fragmento. Devuelve una lista que representa la longitud de cada fragmento de cadena.

4.1.3.2 Ejemplo de entrada y salida

Ejemplo 1:
Entrada: S = "ababcbacadefegdehijhklij"
Salida: [9, 7, 8]
Explicación:
El resultado de la división es "ababcbaca", "defegde", "hijhklij".
Cada letra aparece como máximo en un fragmento.
Divisiones como "ababcbacadefegde", "hijhklij" son incorrectas porque el número de divisiones es menor.

4.1.3.3, solución del problema

Dado que la misma letra sólo puede aparecer en el mismo fragmento, obviamente la posición del subíndice de la primera aparición y la última aparición de la misma letra deben aparecer en el mismo fragmento. Por lo tanto, es necesario recorrer la cadena para obtener la posición del subíndice de la última aparición de cada letra.


Después de obtener la posición del subíndice de la última aparición de cada letra, se puede utilizar un método codicioso para dividir la cadena en tantos segmentos como sea posible. El método específico es recorrer la cadena de izquierda a derecha para obtener el valor máximo de la última aparición de todas las letras en el segmento actual. Cuando se accede al final del subíndice, finaliza el acceso al segmento actual y se busca el siguiente. El segmento continúa hasta que se atraviesa la cuerda.

class Solution {
    
    
    public List<Integer> partitionLabels(String s) {
    
    
        // 统计每个字母最后一次出现的下标位置
        int[] last = new int[26];
        for (int i = 0; i < s.length(); i++) {
    
    
            last[s.charAt(i) - 'a'] = i;
        }
        List<Integer> partition  = new ArrayList<>();
        int start = 0, end = 0;
        // 从左到右遍历字符串,获取当前片段所有字母最后一次出现的最大值end
        for (int i = 0; i < s.length(); i++) {
    
    
            end = Math.max(last[s.charAt(i) - 'a'], end);
            // 当访问到下标end时,当前片段访问结束
            if (i == end) {
    
    
                partition .add(end - start + 1);
                start = end + 1;
            }
        }
        return partition ;
    }
}

Análisis de complejidad

  • Complejidad del tiempo: O(n) , donde n es la longitud de la cadena. Es necesario recorrer la cadena dos veces, registrar la posición del último subíndice de cada letra en el primer recorrido y dividir la cadena en el segundo recorrido.
  • Complejidad espacial: O(∣Σ∣) donde Σ es el conjunto de caracteres de la cadena. En esta pregunta, la cadena contiene sólo letras minúsculas, por lo ∣Σ∣=26.

4.1.4 El mejor momento para comprar y vender acciones II

4.1.4.1, descripción del tema

122. El mejor momento para comprar y vender acciones II

le proporciona una matriz de precios de números enteros, donde prices[i]representa el precio de una determinada acción en iel día.

Cada día, usted puede decidir si comprar y/o vender acciones. No puede poseer más de una acción a la vez. También puedes comprar primero y luego vender el mismo día . Devuelve el máximo

beneficio que puedas obtener .

4.1.4.2, ejemplo de entrada y salida

Ejemplo 1:
Entrada: precios = [7, 1, 5, 3, 6, 4]
Salida: 7
Explicación: comprar el día 2 (precio de las acciones = 1), comprar el día 3 (precio de las acciones = 5) Al vender, esto la transacción puede generar ganancias = 5 - 1 = 4.
Luego, compre el cuarto día (precio de las acciones = 3) y venda el quinto día (precio de las acciones = 6), esta transacción puede generar ganancias = 6 - 3 = 3.
La ganancia total es 4 + 3 = 7.

Ejemplo 2:
Entrada: precios = [1, 2, 3, 4, 5]
Salida: 4
Explicación: comprar el día 1 (precio de las acciones = 1), comprar el día 5 (precio de las acciones = 5) Vender, esta transacción puede hacer una ganancia = 5 - 1 = 4.
La ganancia total es 4.

Ejemplo 3:
Entrada: precios = [7, 6, 4, 3, 1]
Salida: 0
Explicación: En este caso, la transacción no puede obtener una ganancia positiva, por lo que la ganancia máxima se puede obtener al no participar en la transacción, y el beneficio máximo es 0.

4.1.4.3, solución del problema

Dado que no hay límite para la compra de acciones, desde un punto de vista codicioso, puede operar todos los días y elegir un rango donde la ganancia sea mayor que 0. Sin embargo, cabe señalar que, a diferencia de la explicación del ejemplo, El algoritmo codicioso solo se utiliza para calcular el beneficio máximo, y el proceso de cálculo no es el proceso de transacción real.

class Solution {
    
    
    public int maxProfit(int[] prices) {
    
    
        int ans = 0;
        for (int i = 1; i < prices.length; i++) {
    
    
            // 统计利润大于0的区间
            ans += Math.max(0, prices[i] - prices[i - 1]);
        }
        return ans;
    }
}

Análisis de complejidad

  • Complejidad del tiempo: O(n) , donde n es la longitud de la matriz. Sólo necesitamos recorrer la matriz una vez.
  • Complejidad del espacio: O(1) , solo requiere espacio constante para almacenar varias variables.

4.2 Dificultad Avanzada

4.2.1 Reconstruir colas según la altura

4.2.1.1, descripción del tema

406. Reconstruir la cola según la altura

Supongamos que un grupo de personas en orden aleatorio están en una cola y la matriz peoplerepresenta los atributos de algunas personas en la cola (no necesariamente en orden). Cada uno people[i] = [hi, ki]significa que la altura de la i-ésima persona es hi, y hay exactamente una persona cuya kialtura es mayor o igual que al frente. Reconstruya y devuelva la cola representada por la matriz de entrada. La cola devuelta debe tener el formato de una matriz , donde está el atributo de la persona en la cola ( la persona que está al frente de la cola).hi

peoplequeuequeue[j] = [hj, kj]jqueue[0]

4.2.1.2 Ejemplo de entrada y salida

Ejemplo 1:
Entrada: personas = [ [7, 0], [4, 4], [7, 1], [5, 0], [6, 1], [5, 2] ] Salida: [ [
5 , 0], [7, 0], [5, 2], [6, 1], [4, 4], [7, 1] ] Explicación: La altura de la
persona
numerada 0 es 5 y nadie es más alto. o las mismas personas se alinearon delante de él.
La persona numerada 1 tiene una altura de 7, y no hay ninguna persona más alta o igual frente a él.
La altura de la persona numerada 2 es 5, y hay 2 personas con mayor o igual altura frente a él, es decir, personas numeradas 0 y 1.
La altura de la persona número 3 es 6, y hay 1 persona que es más alta o de la misma altura frente a él, es decir, la persona número 1.
La altura de la persona numerada 4 es 4, y hay 4 personas con mayor o igual altura frente a él, es decir, personas numeradas 0, 1, 2 y 3.
La altura de la persona número 5 es 7, y hay 1 persona que es más alta o de la misma altura frente a él, es decir, la persona número 1.
Entonces [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]] es la cola reconstruida.

Ejemplo 2:
Entrada: personas = [ [6, 0], [5, 0], [4, 0], [3, 2], [2, 2], [1, 4] ] Salida: [ [
4 , 0], [5, 0], [2, 2], [3, 2], [1, 4], [6, 0] ]

4.2.1.3, solución del problema

Primero clasifique según la altura de pequeño a grande, los más altos al frente o el mismo número de personas de pequeño a grande, luego recorra la cola ordenada, deje un espacio correspondiente delante de cada elemento y cumpla con las condiciones en la raíz de la pregunta. , puedes Es muy conveniente restaurar la cola original.

class Solution {
    
    
    public int[][] reconstructQueue(int[][] people) {
    
    
        // 按照身高从小到大,前面身高更高或者相同的人数从少到多进行排序
        Arrays.sort(people, new Comparator<int[]>() {
    
    
            @Override
            public int compare(int[] people0, int[] people1) {
    
    
               if (people0[0] != people1[0]) {
    
    
                   return people0[0] - people1[0];
               } else {
    
    
                   return people0[1] - people1[1];
               }
            }
        });
        // 重新构造的队列
        int[][] ans = new int[people.length][];
        
        // 遍历重新排序后的队列
        for (int[] person : people) {
    
    
            // 需重新入队人员的前面身高更高或者相同的人数,为0时则入队
            int index = person[1];
            // 遍历重新构造的队列(未完全完成)
            for (int j = 0; j < ans.length; j++) {
    
    
                if (index == 0) {
    
    
                    if (ans[j] == null) {
    
    
                        ans[j] = person;
                        break;
                    }
                    continue;
                }
                // 确保需入队人员前面身高更高或者相同的人数要求
                if (ans[j] == null || ans[j][0] >= person[0]) {
    
    
                    index--;
                }
            }
        }
        return ans;
    }
}

Análisis de complejidad

  • Complejidad del tiempo: O(n 2 ) , donde n es la longitud de las personas de la matriz. Necesitamos tiempo O(nlogn) para ordenar, y luego tiempo O(n 2 ) para recorrer a cada persona y ponerla en la cola. Dado que el primero es asintóticamente menor que el segundo, la complejidad temporal total es O(n 2 ).
  • Complejidad espacial: O(logn) .

4.2.2 Secuencia no decreciente

4.2.2.1, descripción del tema

665. Secuencia no decreciente

Dada una nmatriz de números enteros con una longitud de nums, juzgue si la matriz puede convertirse en una secuencia no decreciente cambiando como máximo los elementos. Así es como definimos una matriz no decreciente: para cualquiera en la matriz , siempre se satisface .1

i (0 <= i <= n-2)nums[i] <= nums[i + 1]

4.2.2.2 Ejemplo de entrada y salida

Ejemplo 1:
Entrada: nums = [4, 2, 3]
Salida: verdadero
Explicación: Puede convertirla en una secuencia no decreciente cambiando los primeros 4 a 1.

Ejemplo 2:
Entrada: nums = [4, 2, 1]
Salida: false
Explicación: No puedes convertirla en una secuencia no decreciente cambiando solo un elemento.

4.2.2.3, solución del problema

Bajo la premisa de garantizar que se cambie como máximo un elemento, si la matriz se cambia a una secuencia no decreciente, solo necesita atravesar la matriz, modificar y contar cuando encuentre una condición no decreciente, y fallar cuando el segundo cambio ocurre.


Durante el recorrido, cuando el siguiente elemento es más pequeño que el anterior, si es el principio o el final de la matriz, no es necesario cambiar la matriz, solo contar, porque se puede considerar que establece el primer elemento de la matriz. al valor mínimo, o configurando la matriz Al final, pensé que estaba configurado al valor máximo y no se usará más adelante, por lo que no es necesario modificarlo.


Si está en el medio de la matriz, en realidad hay dos métodos de procesamiento en este momento, uno es modificar el valor para que sea el mismo que el valor anterior y el otro es modificar el valor anterior para que sea el mismo que el valor (aquí, es necesario asegurarse de que después de modificar el valor anterior, no afectará su condición no decreciente), aquí debemos usar el segundo método primero, porque este valor debe compararse con los valores posteriores, por lo que debería Asegúrese de que el valor sea lo más pequeño posible.

class Solution {
    
    
    public boolean checkPossibility(int[] nums) {
    
    
        for (int i = 1, count = 0; i < nums.length; i++) {
    
    
            if (nums[i] < nums[i - 1]) {
    
    
                if (i != 1 && i != nums.length - 1 && nums[i] < nums[i - 2]) {
    
    
                    nums[i] = nums[i - 1];
                }
                if (++count > 1) {
    
    
                    return false;
                }
            }
        }
        return true;
    }
}

Análisis de complejidad

  • Complejidad del tiempo: O(n) , donde n es la longitud de los números de la matriz.
  • Complejidad espacial: O(1) .

Supongo que te gusta

Origin blog.csdn.net/rockvine/article/details/125472114
Recomendado
Clasificación