LeetCode 419 BattleshipsInABoard DFS、BFS简单的入门

来源:互联网 发布:怎么看网络是否被劫持 编辑:程序博客网 时间:2024/06/10 01:14
419. Battleships in a Board
Given an 2D board, count how many different battleships are in it. The battleships are represented with 'X's, empty slots are represented with '.'s. You may assume the following rules:
  • You receive a valid board, made of only battleships or empty slots.
  • Battleships can only be placed horizontally or vertically. In other words, they can only be made of the shape 1xN (1 row, N columns) orNx1 (N rows, 1 column), where N can be of any size.
  • At least one horizontal or vertical cell separates between two battleships - there are no adjacent battleships.

Example:

X..X...X...X

In the above board there are 2 battleships.

Invalid Example:

...XXXXX...X


This is not a valid board - as battleships will always have a cell separating between them.
Your algorithm should not modify the value of the board.
class Solution {
public:
    int countBattleships(vector<vector<char>>& board) {
    }
};

解题思路:
  • 自己的解题思路
一开始,题目没有读懂。认为出现Case2的时候,应该返回0;而题目的意思是不考虑这种情况。如果,正确理解题意的话,这题是不怎么难的。但是这题却能扩展出很多知识,并且也让我学到不少新的知识。
思路:设置一个辅助数组,标记该网格有没有被访问到,访问到则为1,未访问则为0。之后,从左往右,从上往下,依次遍历网格,知道找到‘X’为止,接着依次往右再遍历或者往下遍历。因为题目的意思,只存在行或者列的连续X,不存在交叉现象。遍历下来,就可以得到答案。
  • 别人的解题思路
程序2.1  对于特定的X进行累加,【cnt += board[r][c] == 'X' && (r == 0 || board[r - 1][c] != 'X') && (c == 0 || board[r][c - 1] != 'X');】也就是我上面程序开始遍历遇到的第一个X,之后周围的X都可以省略掉。这个程序的运行更快了。
之后的几个程序都是关于这类问题常用的几种方法,DFS和BFS。它们不单可以解决这道题目,还可以解决像Case这样的情况,所以用途更广。
学习收获:
  • 对于vector<vector<int>>这种类型不够熟悉
包括初始化,申请空间,元素的提取。
比较不错的初始化:
  • vector<vector<bool>> flag(m, vector<bool>(n, false));
  • vector<vector<bool>> flag;     flag.resize(m, vector<bool>(n, false));
提取元素: flag[i][j];         
相关扩展阅读,见附件二。
  • 对于二维数组的参数传值,以及如何new一个二维数组,暂时不做过多整理。有兴趣的,可以自己查资料。
  • 学会了使用DFS跟BFS,对于一些简单的遍历可以写出程序。
DFS跟BFS思想很简单。再看着别人的程序,然后自己先码一遍,然后再默写一遍,基本上就over了。当然,在这过程中,你可能会质疑这个pop(),怎么放这里,push(),怎么不放在前面。多思考吧,练练就会了。
强烈推荐看我分享的代码,代码格式很规范,对于学习DFS,BFS很有帮助。
学习完了,可以拿迷宫问题练练手。
【PS:其实,我的内心是崩溃的,为什么我没有早点接触优质代码呢?因为太菜了吧!】
附件1:程序
1、自己的程序:
int countBattleships(vector<vector<char>> board)
{
    //An initialization for e like shit!!! How terrible
    vector<vector<int>> e(board.size());
    for(int i = 0; i != board.size(); ++i)
    {
        e[i].reserve(board[0].size());
        for(int j = 0; j != board[0].size(); ++j)
        {
            e[i].push_back(0);
        }
    }
    int res = 0;
    for(int i = 0; i != board.size(); ++i)
    {
        for(int j = 0; j != board[0].size(); ++j)
        {
            if(e[i][j] == 1)
            {
                continue;
            }
            if(board[i][j] == '.')
            {
                e[i][j] = 1;
            }
            else
            {
                res++;
                int j1 = j;
                while((j1 + 1) != board[0].size() && board[i][j1 + 1] == 'X')
                {
                    ++j1;
                    e[i][j1] = 1;
                }
                int i1 = i;
                while((i1 + 1) != board.size() && board[i1 + 1][j] == 'X')
                {
                    ++i1;
                    e[i1][j] = 1;
                }
            }
        }
    }
    return res;
}
2、别人的程序
int countBattleships(vector<vector<char>>& board)
{
    if(board.empty() || board[0].empty()) { return 0; }
    int m = board.size(), n = board[0].size(), cnt = 0;
    for(int r = 0; r < m; r++)
        for(int c = 0; c < n; c++)
            cnt += board[r][c] == 'X' && (r == 0 || board[r - 1][c] != 'X') && (c == 0 || board[r][c - 1] != 'X');
    return cnt;
}
DFS ( recursive algorithm)
class Solution
{
    public:
    int m, n;
    vector<vector<bool>> flag;
    int go[4][2] = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } };
    void dfs(vector<vector<char>>& board, int i, int j)
    {
        if(i < 0 || i >= m || j < 0 || j >= n || board[i][j] == '.' || flag[i][j]) return;
        flag[i][j] = true;
        for(int d = 0; d < 4; ++d) dfs(board, i + go[d][0], j + go[d][1]);
    }
    int countBattleships(vector<vector<char>>& board)
    {
        if(board.empty()) return 0;
        m = board.size(), n = board[0].size();
        flag.resize(m, vector<bool>(n, false));
        int result = 0;
        for(int i = 0; i < m; ++i)
            for(int j = 0; j < n; ++j)
                if(board[i][j] == 'X' && !flag[i][j])
                {
                    ++result;
                    dfs(board, i, j);
                }
        return result;
    }
};
DFS ( non-recursive algorithm) 【PS:自己参考上面的DFS,写的。因此,也放在这里。】
const int go[4][2] = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } };
class Solution
{
    public:
    int countBattleships(vector<vector<char>>& board)
    {
        if(board.empty())
        {
            return 0;
        }
        int m = board.size();
        int n = board[0].size();
        vector<vector<bool>> flag(m, vector<bool>(n, false));
        int res = 0;
        for(int i = 0; i < m; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                if(board[i][j] == 'X'&&!flag[i][j])
                {
                    flag[i][j] = true;
                    ++res;
                    stack<pair<int, int>> st;
                    st.push({ i, j });
                    while(!st.empty())
                    {
                        auto t = st.top();
//you can ponder why use line43(flag[ni][nj] = true;)  not the below
                        //flag[t.first][t.second] = true;   
                        int d = 0;
                        for(; d < 4; ++d)
                        {
                            int ni = t.first + go[d][0];
                            int nj = t.second + go[d][1];
                            if(ni < 0 || ni >= m || nj < 0 || nj >= n ||
                               board[ni][nj] == '.' || flag[ni][nj])
                            {
                                continue;
                            }
                            flag[ni][nj] = true;
                            st.push({ ni, nj });
                            break;
                        }
                        if(d == 4)
                        {
                            st.pop();
                        }
                    }//while
                }//if
            }//for2
        }//for1
        return res;
    }
};
BFS
class Solution
{
    public:
    int go[4][2] = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } };
    int countBattleships(vector<vector<char>>& board)
    {
        if(board.empty()) return 0;
        int m = board.size(), n = board[0].size();
        vector<vector<bool>> flag(m, vector<bool>(n, false));
        int result = 0;
        for(int i = 0; i < m; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                if(board[i][j] == 'X' && !flag[i][j])
                {
                    ++result;
                    queue<pair<int, int>> q;
                    q.push({ i, j });
                    while(!q.empty())
                    {
                        auto t = q.front(); q.pop();
                        flag[t.first][t.second] = true;
                        for(int d = 0; d < 4; ++d)
                        {
                            int ni = t.first + go[d][0], nj = t.second + go[d][1];
                            if(ni < 0 || ni >= m || nj < 0 || nj >= n || board[ni][nj] == '.' || flag[ni][nj]) continue;
                            q.push({ ni, nj });
                        }
                    }
                }
            }
        }
        return result;
    }
};

附件2:扩展阅读

  1. vector容器assign(),capacity(),size(),swap(),get_allocator(),max_size(),reserve(),resize(). http://blog.csdn.net/qingqinglanghua/article/details/5035763
//这个是一维向量的例子,通过简单的程序,了解几个成员函数的作用。可以快速看看
  1. C++ vector多维数组初始化及清零.
http://blog.csdn.net/xiaxiazls/article/details/50018225
//这是作者整理别人的帖子,里面的内容还不错。涉及二维数组的初始化。【推荐看看前面以及最后的总结】
总结如下:
vector:对于vector赋值方式中,assign的速度是最快的,其次是resize以后用copy算法赋值,而最先能够想到的赋值操作符,速度却并不快,只能够排名第三,目前还不知道这是为什么,采用插入迭代器再用copy的方式是速度最慢的一种。
list:
对于list赋值,赋值操作符的速度是最快的,其次是assign,然后是采用resizecopy,最后一位同样是采用插入迭代子方式的copy
0 0
原创粉丝点击