使用引用避免拷贝
Posted awangkuo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用引用避免拷贝相关的知识,希望对你有一定的参考价值。
在编译力扣1162,地图分析题时,切实的用到了引用的妙用。
题目大意是N*N的地图上,有陆地1,海洋0,寻找离陆地区域的最远的海洋区域,求离其最近的陆地距离,全海洋或全陆地返回-1。
其中这里说的距离是曼哈顿距离:(x0, y0)
和 (x1, y1)
这两个区域之间的距离是 |x0 - x1| + |y0 - y1|
。
在该题目中,我先是遍历寻找每一个海洋区域,找到海洋区域之后再遍历寻找一个离该区域最近的陆地区域的距离,这样每一个海洋都有了一个离其最近的陆地的距离。
那么在这些最近距离中,最长的那个距离一定是是离所有的陆地最远的。代码如下:
class Solution { public: int maxDistance(vector<vector<int>>& grid) { int md=-1; for(int i=0;i<grid.size();i++) { for(int j=0;j<grid[0].size();j++) { if(grid[i][j]==0) { //证明这是一快海洋,现在可以寻找离他最近的陆地的距离 //这块海洋得里所有的陆地都远 md=max(md,dis(grid,i,j)); } } } return md; } int dis(vector<vector<int>> grid,int a,int b) { int distance=INT_MAX; for(int i=0;i<grid.size();i++) { for(int j=0;j<grid[0].size();j++) { if(grid[i][j]==1) { int ta,tb; if(a>i) ta=a-i; else ta=i-a; if(b>j) tb=b-j; else tb=j-b; distance=min(tb+ta,distance); } } } if(distance==INT_MAX)//全是海洋 return -1; return distance; } };
但是,这个代码是有缺陷的,也就是不能通过力扣的样例,它超出了时间限制。
为此,为了减小时间上的花费,我们对其进行改进,观察之后不难发现每次寻找离该海洋区域最小距离的陆地时,我们白白遍历了整个数组,这是不讨好的,意味着我们找到最小距离之后做了
大量的无用功,那么如何改进呢?事实上,我们寻找的离该区域的最小距离陆地也是从距离1开始的,在与该海洋距离为1的所有块中只要有陆地1就可以跳出返回该值得,若没有,逐步扩大这个距离
,直到找到陆地。这时候已经用了最小的花费,距离比该值大的不会再考虑在内,省去了大量无用功。
每一个距离的判断中,我们判断的是与其横坐标和纵坐标之差的绝对值等于距离r的点我们说,若与横坐标相差x,那么就与纵坐标相差y=r-x。x从0开始递增直到等于r就可以囊括所有的距离情况。
改进后的代码如下:
class Solution { public: int maxDistance(vector<vector<int>>& grid) { int md=-1; for(int i=0;i<grid.size();i++) { for(int j=0;j<grid[0].size();j++) { if(grid[i][j]==0) { //证明这是一快海洋,现在可以寻找离他最近的陆地的距离 //这块海洋得里所有的陆地都远 md=max(md,dis(grid,i,j)); } } } return md; } int dis(vector<vector<int>> grid,int a,int b) { int distance=INT_MAX;//寻找离此海洋距离最近的一块陆地 int N=grid.size(); int r=1; int D=max((a+b),(N-1-b+a)); D=max(D,(N-1-a+b)); D=max(D,(N-1-a+N-1-b)); for(r;r<=D;r++) { //上下左右 bool s=false; for(int x=0;x<=r;x++) { int y=r-x; if(a-x>=0 && b-y>=0 && grid[a-x][b-y]==1) { s=true; break; } else if(a-x>=0 && b+y<N && grid[a-x][b+y]==1) { s=true; break; } else if(a+x<N && b-y>=0 && grid[a+x][b-y]==1) { s=true; break; } else if(a+x<N && b+y<N && grid[a+x][b+y]==1) { s=true; break; } } if(s) { //证明找到了小岛 distance=r; break; } } if(distance==INT_MAX)//全是海洋 return -1; return distance; } };
提交这个代码之后,时间超出限制的例子是通过了,可是又出现了新的问题,不得不说力扣的测试样例确实全面,很多情况都会囊括在内。
这次的问题是超出了内存限制,是什么情况呢?原来,每次的调用最小距离函数开销巨大,虽然我们不再进行全数组遍历操作,可是问题每次调用函数的时候我们向函数内传参
每一次的传参都相当于对数组的一次拷贝,会不会可以使用引用呢?我就冒然试了一下,加了一个引用符号,果然通过了。这次是百分百通过了所有案例,至此解题成功,正确代码
如下,比上一代码多了一个引用符号。
class Solution { public: int maxDistance(vector<vector<int>>& grid) { int md=-1; for(int i=0;i<grid.size();i++) { for(int j=0;j<grid[0].size();j++) { if(grid[i][j]==0) { //证明这是一快海洋,现在可以寻找离他最近的陆地的距离 //这块海洋得里所有的陆地都远 md=max(md,dis(grid,i,j)); } } } return md; } int dis(vector<vector<int>> &grid,int a,int b) { int distance=INT_MAX;//寻找离此海洋距离最近的一块陆地 int N=grid.size(); int r=1; int D=max((a+b),(N-1-b+a)); D=max(D,(N-1-a+b)); D=max(D,(N-1-a+N-1-b)); for(r;r<=D;r++) { //上下左右 bool s=false; for(int x=0;x<=r;x++) { int y=r-x; if(a-x>=0 && b-y>=0 && grid[a-x][b-y]==1) { s=true; break; } else if(a-x>=0 && b+y<N && grid[a-x][b+y]==1) { s=true; break; } else if(a+x<N && b-y>=0 && grid[a+x][b-y]==1) { s=true; break; } else if(a+x<N && b+y<N && grid[a+x][b+y]==1) { s=true; break; } } if(s) { //证明找到了小岛 distance=r; break; } } if(distance==INT_MAX)//全是海洋 return -1; return distance; } };
现在,在此题中又一次感受到了引用带来的好处。
primer189页原句如下:
使用引用避免拷贝
拷贝大的类类型对象或者容器对象比较低效,甚至有的类类型(包括IO类型在内)根本就不支持拷贝操作。当某种类型不支持拷贝操作时,函数只能通过引用形参访问该类型的对象。
以上是关于使用引用避免拷贝的主要内容,如果未能解决你的问题,请参考以下文章
什么时候可以在android中使用强引用,这个代码是否泄漏?
需要一种有效的方法来避免使用 Laravel 5 重复代码片段
Android 逆向使用 DB Browser 查看并修改 SQLite 数据库 ( 从 Android 应用数据目录中拷贝数据库文件 | 使用 DB Browser 工具查看数据块文件 )(代码片段
Android 逆向使用 DB Browser 查看并修改 SQLite 数据库 ( 从 Android 应用数据目录中拷贝数据库文件 | 使用 DB Browser 工具查看数据块文件 )(代码片段