以下递归代码的时间复杂度是多少

时间:2018-09-10 06:17:04

标签: c++ algorithm recursion time-complexity

不确定是否相关,但是我要解决的问题是

~~~~~~~~~~~~~与所有建筑物的最短距离~~~~~~~~~~~~~~~~

您要在空旷的土地上盖房子,该土地应以最短的距离到达所有建筑物。您只能上下左右移动。您将获得一个二维网格,其值为0、1或2,其中:

每个0标记一个空地,您可以自由通过。 每个1代表您无法通过的建筑物。 每2个标志都是您无法通过的障碍。

找到可以进入所有建筑物的空地的最小距离 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~

尽管我的解决方案可以在小输入上正常工作,但由于时间复杂度高,对于较大的输入却会超时。

但是我不确定该解决方案的确切时间复杂度,并想正确理解该解决方案的时间复杂度是什么,以便在可能的情况下尝试改善它。

我非常确定外部循环的时间复杂度是O(MN)(M是总行数,N是总行数),因为我们正在遍历网格的所有位置,但是我我不确定递归shortDist方法的时间复杂度。是否也是O(MN),因为在最坏的情况下它将接触网格的每个位置,因此此解决方案的总时间复杂度将为O(M ^ 2 * N ^ 2)或其他(如果是)如果有人可以向我解释一下,那就太好了。

我的解决方法是

class Solution {
public:
    int shortestDistance(vector<vector<int>>& grid) {

        vector<std::pair<int,int>> dir = {{-1,0}, {1,0}, {0,-1}, {0,1}};
        // pair(row, col) -> distance
        map<std::pair<int,int>, int> cache;
        vector<vector<bool>> visited(grid.size(), vector<bool>(grid[0].size(), false)); // to check if we have already visited that location on the grid
        int minDist = INT_MAX;
        int maxCount =0;
        // Finding number of 1's
        for(int i =0; i< grid.size(); i++)
        {
            for(int y =0; y < grid[0].size(); y++)
            {
                if(grid[i][y] == 1)
                {
                    maxCount++;
                }
            }
        }
        // For each 0 find the distance of each 1's and their count
        // if the count of 1's is less than the number of 1's in the
        // grid that grid position is not an acceptable pos
        for(int i =0; i< grid.size(); i++)
        {
            for(int y =0; y < grid[0].size(); y++)
            {
                if(grid[i][y] == 0)
                {
                    shortDist(grid, cache, dir, visited, i, y, 0);
                    int dist =0;
                    int count = cache.size();// number of 1's
                    if(count == maxCount)
                    {
                        // if we are here it implies that the empty land space have path to all the buildings
                        for(auto iter = cache.begin(); iter != cache.end(); iter++)
                        {
                            dist += iter->second;
                        }
                        if(dist < minDist)
                        {
                            minDist = dist;
                        }
                    }
                    cache.clear();
                }       
            }
        }

        return minDist == INT_MAX ? -1 : minDist;

    }

    void shortDist(vector<vector<int>>& grid, map<std::pair<int,int>, int>& cache, vector<std::pair<int,int>>& dir, vector<vector<bool>>& visited, int row, int col, int dist)
    {
        if(row < 0 || col < 0 || row >= grid.size() || col >= grid[0].size())
        {
            return;
        }
        if(grid[row][col] == 2)
        {
            return;
        }
        if(grid[row][col] == 1)
        {
            auto found = cache.find(make_pair(row, col));
            if(found == cache.end())
            {
                cache[(make_pair(row, col))] = dist;
            }
            else
            {
                found->second = min(found->second, dist);
            }

            return;
        }

        if(visited[row][col])
        {
            return;
        }

        visited[row][col] = true;
        for(int i =0; i < dir.size(); i++)
        {
            int newRow = row + dir[i].first;
            int newCol = col + dir[i].second;
            shortDist(grid, cache, dir, visited, newRow, newCol, dist+1);
        }
        visited[row][col] = false;
    }
};

1 个答案:

答案 0 :(得分:1)

据我所知shortDist是主要贡献者。

函数shortDist的{​​{1}}具有O(log(MN)),因为缓存可以最大包含行* cols项,(使用find,使用{{1} }只有O(1)(如果您有完善的哈希函数)。然后您递归得出D = max(M,N)的距离,实际上,您访问了每个MN点。对于来自std::map的每个呼叫总计O(MN log(MN))。

std::unordered_map中,网格上的第二个循环的前两个循环具有O(MN),然后在高速缓存中具有O(MN),给出O(M ^ 2 * N ^ 2),调用shortDist是O(M ^ 2N ^ 2 log(MN))。

如果您使用另一个MN数组直接查找值,则可以保存log(MN)。

实施优化。

您对shortDist的调用包含太多参数。

shortestDistance向量应该是constexpr std :: array,因为它永远不会改变,并且会在所有搜索中使用。

shortestDistancedir应该是该类的成员,对于每个调用,shortestDistance都会重置,如果不是的话,Solution实例仅使用一次。

使用网格拖动作为参数似乎也很浪费,因为您需要执行几次。将其设置为类引用或副本即可解决此问题。

然后Cache仅具有合理的3个参数。

通过使网格成为一维并计算自己的索引,可以将visited中的每个x,y查找从两次访问减少到一次,可以节省很多性能损失。