使用引用避免拷贝

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 工具查看数据块文件 )(代码片段

Chapter13:拷贝控制