LeetCode 42. Recibiendo agua de lluvia (dos consejos resueltos inteligentemente y la imagen de Wayne es asombrosa)

Sábado 13 de marzo de 2021, hace buen tiempo [No lamentes el pasado, no desperdicies el presente, no temas el futuro]


1. Introducción

42. atrapa la lluvia
Inserte la descripción de la imagen aquí

2. Una variedad de soluciones (las matemáticas son las más ingeniosas)

Para obtener más información, consulte: https://leetcode-cn.com/problems/trapping-rain-water/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa -por- w-8 /

2.1 Buscar por columna (paso a paso)

2.1.1 Ley violenta (doble bucle)

Método de fuerza bruta: atraviese la matriz, calcule el valor límite de los lados izquierdo y derecho con un bucle cada vez y luego obtenga el volumen de agua en esta columna.

Aunque la ley de violencia es muy compleja en el tiempo O(n*n), después de comprender la ley de violencia, se puede mejorar para obtener un método mejor.

class Solution {
    
    
public:
    int trap(vector<int>& height) {
    
       
        const int n = height.size();
        int res = 0;
        for(int i=1;i<n-1;++i){
    
    
            int max_left = 0, max_right = 0;

            for(int j=i;j>=0;--j)
                max_left = max(max_left,height[j]);
            for(int j=i;j<n;++j)
                max_right = max(max_right,height[j]);
                
            res += min(max_left,max_right)-height[i];
        }
        return res;
    }
};

2.1.2 Programación unidinámica de optimización de la ley de violencia

Cuando el método de fuerza bruta calcula los valores límite de los lados izquierdo y derecho, hay una gran cantidad de cálculos repetidos, por lo que la programación dinámica se puede utilizar para almacenar resultados intermedios y reducir la complejidad del tiempo a O(n).

class Solution {
    
    
public:
    int trap(vector<int>& height) {
    
       
        if(height.empty()) return 0;
        const int n = height.size();
        int ans = 0;
        vector<int> max_left(n), max_right(n);
        max_left[0] = height[0];
        max_right[n-1] = height[n-1];

        for(int i=1;i<n;++i)
            max_left[i] = max(max_left[i-1],height[i]);
        for(int i=n-2;i>=0;--i)
            max_right[i] = max(max_right[i+1],height[i]);
        for(int i=0;i<n;++i)
            ans += min(max_left[i],max_right[i])-height[i];

        return ans;
    }
};

2.1.3 Optimización de métodos violentos de dos punteros dobles, solución inteligente

El método de doble puntero también es una mejora del método violento. Destaca uno 左右横跳. El lado que esté más alto en los lados izquierdo y derecho atravesará el otro lado y calculará el almacenamiento de agua de la columna que se está atravesando. Después de dicho recorrido, saldrá el resultado, y solo se necesita un espacio constante.

class Solution {
    
    
public:
    int trap(vector<int>& height) {
    
    
        if(height.empty()) return 0;
        int i = 0, j = height.size()-1;
        int left_max = height[i], right_max = height[j];
        int ans = 0;
        while(i<j){
    
    
            if(height[i]<=height[j]){
    
    
                ++i;
                left_max = max(left_max,height[i]);
                if(height[i]<left_max)
                ans += left_max-height[i];    
            }
            else {
    
    
                --j;
                right_max = max(right_max,height[j]);
                if(height[j]<right_max)
                ans += right_max-height[j];    
            }
        }
        return ans;
    }
};

2.2 Buscar por línea (pila monótona)

La pila monótona se resuelve por línea y la idea es más difícil de entender. El principio general es:

  • Cuando la altura actual es menor o igual que la altura de la parte superior de la pila, la pila se empuja y el puntero se mueve hacia atrás.

  • Cuando la altura actual es mayor que la altura de la parte superior de la pila, saque la pila y luego calcule la capacidad de almacenamiento de agua de la fila del área encerrada por la parte superior de la pila actual y la altura actual hasta que la altura de la pared actual sea menor o igual a la altura superior de la pila o la pila vacía, y luego coloque la pared actual en la pila, puntero Mover hacia atrás.

class Solution {
    
    
public:
    int trap(vector<int>& height) {
    
    
        const int n = height.size();
        stack<int> st;
        int res = 0, cur = 0;
        while(cur<n){
    
    
            while(!st.empty() && height[st.top()]<height[cur]){
    
    
                int top = height[st.top()];
                st.pop();
                if(st.empty()) break;

                int d = cur-st.top()-1;
                int h = min(height[cur],height[st.top()])-top;
                res += d*h;
            }
            st.push(cur++);
        }
        return res;
    }
};

2.3 Método matemático (diagrama de Venn, absolutamente impresionante)

Este método se vio accidentalmente en la solución del problema de leetcode: https://leetcode-cn.com/problems/trapping-rain-water/solution/wei-en-tu-jie-fa-zui-jian-dan- yi-dong -10xing-jie-j / , usando el diagrama de Venn para resolver, se puede decir que el cerebro está completamente abierto y solo se requiere una complejidad espacial constante.

s_right:Suponiendo que el extremo derecho está cerrado, la cantidad de lluvia
Inserte la descripción de la imagen aquí
s_left:que se puede recibir se cierra y la cantidad de lluvia que se puede recibir
Inserte la descripción de la imagen aquí
s_rect:se cierra en ambos lados, y la cantidad de lluvia que se puede recibir es el área del rectángulo completo.

s_zhu :Área de la columna
Inserte la descripción de la imagen aquí

Se puede ver en el área sombreada de la figura anterior:s_left + s_right - s_rect = s_zhu + res

class Solution {
    
    
public:
    int trap(vector<int>& height) {
    
    
        if(height.empty()) return 0;
        const int n = height.size();
        int left_max = height[0], right_max = height[n-1];
        // s_left:假设最左边是封闭的,能接到的雨水量
        // s_right:假设最右边是封闭的,能接到的雨水量
        // s_rect:假设两边都是封闭的,能接到的雨水量,也就是矩形的面积
        // s_left + s_right - s_rect = s_zhu + res
        int s_left = 0, s_right = 0, s_zhu = 0, h_max = height[0];
        for(int i=0;i<height.size();++i){
    
    
            left_max = max(left_max,height[i]);
            s_left += left_max;
            right_max = max(right_max,height[n-1-i]);
            s_right += right_max;

            h_max = max(h_max,height[i]);   
            s_zhu += height[i];
        }
        int s_rect = h_max*n;
        return s_left + s_right - s_zhu - s_rect;
    }
};

referencias

https://leetcode-cn.com/problems/trapping-rain-water/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-8/

https://leetcode-cn.com/problems/trapping-rain-water/solution/wei-en-tu-jie-fa-zui-jian-dan-yi-dong-10xing-jie-j/

Supongo que te gusta

Origin blog.csdn.net/m0_37433111/article/details/114736417
Recomendado
Clasificación