LeetCode 419 BattleshipsInABoard DFS、BFS簡單的入門

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:

...X

XXXX

...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多維數組初始化及清零.
//這是作者整理別人的帖子,裏面的內容還不錯。涉及二維數組的初始化。【推薦看看前面以及最後的總結】
總結如下:
vector:對於vector賦值方式中,assign的速度是最快的,其次是resize以後用copy算法賦值,而最先能夠想到的賦值操作符,速度卻並不快,只能夠排名第三,目前還不知道這是爲什麼,採用插入迭代器再用copy的方式是速度最慢的一種。
list:
對於list賦值,賦值操作符的速度是最快的,其次是assign,然後是採用resizecopy,最後一位同樣是採用插入迭代子方式的copy
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章