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