水坑面积

本文深入探讨了一维和二维水坑面积问题的算法解决方案,通过遍历数组和矩阵,寻找能够积水的位置,详细讲解了如何利用优先级队列进行高效计算,旨在帮助读者理解并掌握此类算法题目的解决思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一维水坑面积

是的,如上,我是一个懒人在这里插入图片描述
输入是一个数组,数组中的元素代表每一个位置的房子的高度,输出积水量。
举例输入
5 7 6 10 7 5 4 5 7
输出
7
思路
遍历数组的每一个元素,找到当前元素左边的最高值,右边的最高值,则改元素能形成的积水量=min(左边最高值,右边最高值)-当前元素值(当然前面的最小值要小于当前元素值)。
但这样直接的方式时间复杂度就是 O ( n 2 ) O(n^2) O(n2),考虑先遍历一次,将每个元素右边的最大值存储起来,然后再从左往右遍历一次,在这次遍历中,对于每一个元素先找到其左边的最大值(将当前值和左边最大值比较),然后计算当前位置的积水量,这样时间复杂度就是 O ( n ) O(n) O(n),空间复杂度也是 O ( n 2 ) O(n^2) O(n2),因为用了一个数组来存每个元素右边的最大值。

class Solution {
public:
    int trap(vector<int>& height) {
        int water=0;
        if(height.size()<3) return water;
        
        int LL=0,RL=0;
        vector<int> right(height.size());
        for(int i=height.size()-1;i>=0;i--){
            
            RL=max(height[i],RL);
            right[i]=RL;
        }
        for(int i=0;i<height.size();i++){
           
            LL=max(height[i],LL);
            water+=min(LL,right[i])>height[i]?min(LL,right[i])-height[i]:0;
        }
        return water;
        
    }
};

二维水坑面积问题(leetcode 407)
问题:给定一个m*n的矩阵,表示每一个块的高度,根据这个矩阵,计算能积水多少。
example:

Given the following 3x6 height map:
[
  [1,4,3,1,3,2],
  [3,2,1,3,2,4],
  [2,3,3,2,3,1]
]

Return 4.

上图取自leetcode,是给定的矩阵的示意图。

上图同取自leetcode,蓝色部分表示能积攒的水量。

分析:
一维的情况是,当前块儿的高度低于两侧的高度,就能积水,同理,二维的情况时,当前块儿的高度低于它四周的高度就能积水。So,采取BFS遍历当前块儿周围的块儿,判断周围的高度是否比当前的高,高的话,周围的块儿的最高值和当前块儿的差值就是能存储的水量。当然,边界上的肯定不能积水,可以先处理边界的块儿,遍历边界的块儿挨着的中间的块儿。参考了一篇博客的内容,它讲述的十分详细且有图片示意。维护一个变量mx来表示当前的海平面高度,从1开始。每次从高度最小的块儿开始遍历,所以可以使用优先级队列来存储每个块儿,这样每次能返回高度最矮的块儿。一层高度的块儿遍历完之后,mx值加1,遍历第二层的块儿,以此类推,直到遍历完所有的块儿。同时,为了实现这个操作,需要维护一个矩阵,表示每个块是否被访问。
综上

  • 定义一个mx变量,存储当前海平面高度;
  • 需要定义一个优先级队列,里面存储每个块儿的高度和它的索引,为实现BFS则让每一次返回的都是高度最小的块儿,同时每遍历完一个块儿,就把它周围的块儿push进去;
  • 定一个与输入矩阵一样大小的矩阵visited,记录每个块儿是否被访问过;

  • 先将边界点放进优先级队列中,且都标记为已访问过;
  • 遍历队列,每次获取高度最小的那个;
  • 按照BFS的顺序遍历周围的块儿,更新mx,更新访问状态,将该块儿加入que;
  • 更新res(若mx比当前块儿高,则res加上两者的差值)。
class Solution {
public:
    int trapRainWater(vector<vector<int>>& heightMap) {
        int res=0;
        if(heightMap.empty()) return res;
        int rows=heightMap.size(),cols=heightMap[0].size();
        int mx=INT_MIN;
        priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > que;
        vector<vector<bool> > visited(rows,vector<bool>(cols,false));//记录每个块儿是否访问过
        vector<vector<int> > direction={{1,0},{-1,0},{0,1},{0,-1}};//用来控制方向
        
        //先将边界的块儿的高度放进优先级队列中
        for(int i=0;i<rows;i++){
            for(int j=0;j<cols;j++){
                if(i==0 || i==rows-1 || j==0 ||j==cols-1){
                    que.push(make_pair(heightMap[i][j],i*cols+j));
                    visited[i][j]=true;
                }
            }
        }
       
       //遍历que
        while(!que.empty()){
            auto cur=que.top();//获取最矮的
            que.pop();
            int height=cur.first;
            int x_row=cur.second/cols;//解压对应的行列索引
            int y_col=cur.second%cols;
            mx=max(mx,height);
            for(int i=0;i<direction.size();i++){//按BFS的顺序
                int x=x_row+direction[i][0];int y=y_col+direction[i][1];
                if(x<0 || x>=rows ||y<0 || y>=cols ||visited[x][y]==true)   continue;
                visited[x][y]=true;//更新访问记录
                res+=mx>heightMap[x][y]?mx-heightMap[x][y]:0;//更新res
                que.push(make_pair(heightMap[x][y],x*cols+y));//更新que
            }
        }
        return res;
        
    }
};

总结

  • 上面的代码参考上面的博客,que中存储的值是块儿的高度和对应的索引,用了一个十分巧妙的办法,将二维矩阵的索引进行了压缩。索引表示为cols*i+j,这样在后面遍历每个元素的时候,解压表示为x_row=cur.second/cols; y_col=cur.second%cols;
  • 优先级队列的使用
#include <queue>
priority_queue<int> q; //从大到小出
priority_queue<int,vector<int>,less<int> > q; //同上
priority_queue<int,vector<int>,greater<int> > q; //从小到大出,P.S 最后那个> 要空一格,不然就成右移操作了

// greater也可以自定义,就像比较大小的函数,定义一个cmp,并传入
priority_queue<int,vector<int>,cmp> q;

//还可以定义结构体
//比如定义二叉树常用的一个node
priority_queue<node> q;

//basic op
q.empty();
q.size();
q.top();
q.pop();
q.push();
  • pair的用法
//pair用于表示一种关联关系,key-value
//define
pair<string,int> p;
p.first='hello';
p.second=2;

pair<string,int> q1('world',3);
make_pair<string,int>('test',4);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值