42. Recepción de agua de lluvia (pila monótona / prefijo de registro bidireccional / doble puntero) 407. Recepción de agua de lluvia 2 (cola de prioridad + bfs)

42. atrapa la lluvia

Cuando hice esta pregunta por primera vez, recordé que era la solución de mantener una cola monótona. Echemos un vistazo ahora. Está bien, para mantener una cola monótona. Mientras registramos la altura, también debemos registrar el ancho de esta altura. Por lo tanto, se usa una estructura y, debido a que la cola es un formulario primero en entrar, último en salir, pero también necesita acceder al encabezado de la cola, es más apropiado usar deque para una consideración integral.

Para conocer la diferencia específica entre cola y deque, consulte  https://zhuanlan.zhihu.com/p/77981148

class Solution {
public:
    struct node
    {
        int h,x;
        node(int h,int x):h(h),x(x){}
    };
    int trap(vector<int>& height) {
        int n=height.size();
        if (n==0) return 0;
        deque<node> dq;
        node w(height[0],1);
        dq.push_back(w);
        int ans=0;

        for (int i=1;i<n;i++)
        {
            if (height[i]>=dq.front().h)
            {
                int hnow=dq.front().h;
            
                while (!dq.empty())
                {
                    ans+=(hnow-dq.back().h)*dq.back().x;
                    dq.pop_back();
                }

                dq.push_back(node(height[i],1));
            }
            else
            {
                int hnow=height[i];
                int xnow=1;
            
                while (height[i]>=dq.back().h)
                {
                    ans+=(hnow-dq.back().h)*dq.back().x;
                    xnow+=dq.back().x;
                    dq.pop_back();
                }

                dq.push_back(node(height[i],xnow));
            }
        }
        return ans;
    }
};

Además, parece que hay un método de grabación bidireccional , vamos a Kangkang, es decir, la forma de grabar el prefijo más grande y el sufijo más grande es la misma que la idea de grabar la suma de prefijo y sufijo. Es decir, la intención original del título es que para cada elemento de la matriz, encontremos la posición más alta que el agua puede alcanzar después de la lluvia, que es igual al valor menor de la altura máxima en ambos lados menos el valor de altura actual, entonces

algoritmo

Encuentre la altura de barra más alta left_max desde el subíndice i hasta el extremo más a la izquierda de la matriz.
Encuentre la altura de barra más alta right_max desde el subíndice i hasta el extremo derecho de la matriz.
Escanee la altura de la matriz y actualice la respuesta:
acumule min (max_left [i], max_right [i]) - height [i] to ans

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

};

Pero esto cuesta O (2n) complejidad de espacio, y deque solo necesita O (n), pero si encuentra esta pregunta durante la entrevista, se recomienda utilizar este método de grabación bidireccional, que es más fácil de entender y más fácil de codificar.

Bien, encontré la pregunta que registra el producto de prefijos y sufijos    238.    Comparemos y registremos el producto de arreglos distintos a él mismo .

class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
        int n=nums.size();
        vector<int> ans(n);
        vector<int> left_mul(n),right_mul(n);
        left_mul[0]=1;
        for (int i=1;i<n;++i)
        left_mul[i]=nums[i-1]*left_mul[i-1];
        right_mul[n-1]=1;
        for (int i=n-2;i>=0;--i)
        right_mul[i]=nums[i+1]*right_mul[i+1];

        for (int i=0;i<n;i++)
        ans[i]=left_mul[i]*right_mul[i];

        return ans;

    }
};

También hay un algoritmo de doble puntero , que es muy inteligente.

Teorema 1: En cierta posición i, la cantidad de agua que puede almacenar depende del menor de los valores máximos en los lados izquierdo y derecho.

Teorema 2: Cuando procesamos de izquierda a derecha al subíndice izquierdo, el valor máximo left_max a la izquierda es creíble para él, pero right_max no lo es para él.

Teorema 3: Cuando procesamos de derecha a izquierda al subíndice derecho, el valor máximo de right_max a la derecha es creíble para él, pero left_max no lo es para él.

Para la posición left, el valor máximo en el lado izquierdo debe ser left_max, y el valor máximo en el lado derecho es "mayor o igual" que right_max. En este momento, si es left_max<right_maxcierto, entonces sabe cuánta agua puede almacenar. Si habrá un right_max más grande a la derecha en el futuro, no afectará este resultado. Entonces left_max<right_max, cuando esperamos lidiar con el índice izquierdo, por el contrario, queremos lidiar con el subíndice derecho.

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

};

Resumen: De hecho, mi método de escritura inicial es un poco largo. De hecho, se puede resolver mediante una pila monótona. No es necesario juzgar el elemento en la parte inferior de la pila. Solo necesita compararlo con el elemento en la parte superior de la pila una vez y luego guardar el subíndice, porque no hay forma de almacenar la altura. Registre la información de ancho del subíndice, pero si se registra el subíndice i, la información de altura se puede obtener mediante la altura [i], y la información de ancho se puede obtener restando el subíndice. (Tenga en cuenta que la resta aquí es la resta de top () - 1, es decir, ab en la pila es actualmente c, y altura [b] <altura [c] entonces dis = c-a + 1; este procesamiento puede resolver el bloque actual El problema de registrar solo la información de ancho es aún más intuitivo de calcular restando el más grande en ambos lados de la ranura del más pequeño en el medio).

407. atrapa la lluvia 2

Se puede ver en Rainwater 1 que debe ser un pozo para acumular agua. El mantenimiento es unidimensional, pero aquí es para mantener el bidimensional. Originalmente, ambos lados deben mantenerse, pero ahora se debe mantener un círculo . Este es el primero Dificultad, la segunda dificultad es que es difícil pensar en cómo mantenerlo. Aquí, usamos la cola de prioridad para encontrar la tabla más corta en el círculo y gradualmente vertimos agua hacia adentro. La magia es que el círculo original no se destruirá si se mueve gradualmente hacia adentro. La naturaleza del círculo es equivalente a regar en cuatro direcciones, y el tablero se reconstruirá. La plantilla utilizada en esta pregunta es la plantilla del bfs que recorre el laberinto, y cambia de cola a priority_queue, por lo que parece ser una cola de prioridad normal + bfs arriba.

class Solution {
private:
    int foot[4][2]={-1,0,1,0,0,-1,0,1};

    struct node
    {
        int x,y,h;
        node(int x,int y,int h):x(x),y(y),h(h) {}
        friend bool operator < (node a,node b)
        {
            return a.h>b.h;
        }
    };
public:
    int trapRainWater(vector<vector<int>>& heightMap) {
        if (heightMap.size()==0 || heightMap[0].size()==0) return 0;
        int n=heightMap.size(),m=heightMap[0].size();
        priority_queue<node> q;
        bool vis[n+10][m+10];
        memset(vis,0,sizeof(vis));
        vector<vector<int>> hm(n+10,vector<int>(m+10,0));
        for (int i=0;i<=n+1;i++)
        for (int j=0;j<=m+1;j++)
        {
            if (i==0 || i==n+1 || j==0 || j==m+1)
                vis[i][j]=true;
            else
            {
                hm[i][j]=heightMap[i-1][j-1];
                if (i==1 || i==n || j==1 || j==m)
                {
                    q.push({i,j,hm[i][j]});
                    vis[i][j]=true;
                }
            }
        }
        int ans=0;
        while (!q.empty())
        {
            node w=q.top();
            q.pop();
            for (int i=0;i<4;i++)
            {
                int x=w.x+foot[i][0];
                int y=w.y+foot[i][1];
                if (!vis[x][y])
                {
                    if (hm[x][y]>=w.h)
                    {
                        q.push({x,y,hm[x][y]});
                        vis[x][y]=true;
                    }
                    else
                    {
                        ans+=w.h-hm[x][y];
                        q.push({x,y,w.h});
                        vis[x][y]=true;
                    }
                }
            }
        }
        return ans;
    }
};

Nota:

1. Recuerde ampliar la matriz vis y hm

2.q.push ({i, j, hm [i] [j]}); es una forma de escribir, q.push (node ​​(i, j, hm [i] [j])); también debe ser un Escritura.

Entonces, debido a que moví la matriz original de [0..n-1] [0..m-1] a [1..n] [1..m], fue un poco complicado escribirlo. Si no la movía, podría escribir más Simple, vea a continuación.

class Solution {
private:
    int foot[4][2]={-1,0,1,0,0,-1,0,1};

    struct node
    {
        int x,y,h;
        node(int x,int y,int h):x(x),y(y),h(h) {}
        friend bool operator < (node a,node b)
        {
            return a.h>b.h;
        }
    };
public:
    int trapRainWater(vector<vector<int>>& heightMap) {
        if (heightMap.size()==0 || heightMap[0].size()==0) return 0;
        int n=heightMap.size(),m=heightMap[0].size();
        priority_queue<node> q;
        bool vis[n+10][m+10];
        memset(vis,0,sizeof(vis));

        for (int i=0;i<n;i++)
            for (int j=0;j<m;j++)
            if (i==0 || i==n-1 || j==0 || j==m-1)
            {
                q.push(node(i,j,heightMap[i][j]));
                vis[i][j]=true;
            }
        int ans=0;
        while (!q.empty())
        {
            node w=q.top();
            q.pop();
            for (int i=0;i<4;i++)
            {
                int x=w.x+foot[i][0];
                int y=w.y+foot[i][1];
                if (x>=0 && x<n && y>=0 && y<m && !vis[x][y])
                {
                    if (heightMap[x][y]<w.h)
                        ans+=w.h-heightMap[x][y];
                    q.push(node(x,y,max(w.h,heightMap[x][y])));
                    vis[x][y]=true;
                }
            }
        }
        return ans;
    }
};

Esta idea en la solución del problema se siente más clara, puede consultar:

https://leetcode-cn.com/problems/trapping-rain-water-ii/solution/407-jie-yu-shui-zui-xiao-dui-cjie-fa-by-he-qian-3/

 

 

Supongo que te gusta

Origin blog.csdn.net/hbhhhxs/article/details/107805446
Recomendado
Clasificación