LeetCode 419 BattleshipsInABoard DFS、BFS简单的入门

本文解析了计数战舰算法的问题定义与解决方案,重点介绍了如何遍历二维矩阵以识别独立战舰的数量,并探讨了不同遍历策略如DFS和BFS的应用。同时,文章还提供了代码实现案例并讨论了vector容器的高效使用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.youkuaiyun.com/qingqinglanghua/article/details/5035763
//这个是一维向量的例子,通过简单的程序,了解几个成员函数的作用。可以快速看看
  1. C++ vector多维数组初始化及清零.
//这是作者整理别人的帖子,里面的内容还不错。涉及二维数组的初始化。【推荐看看前面以及最后的总结】
总结如下:
vector: 对于 vector 赋值方式中, assign 的速度是最快的,其次是 resize 以后用 copy 算法赋值,而最先能够想到的赋值操作符,速度却并不快,只能够排名第三,目前还不知道这是为什么,采用插入迭代器再用 copy 的方式是速度最慢的一种。
list:
对于 list 赋值,赋值操作符的速度是最快的,其次是 assign ,然后是采用 resize copy ,最后一位同样是采用插入迭代子方式的 copy
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值