LeetCode DFS、BFS篇(102、200、111、752)
102. 二叉树的层序遍历
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
示例:
二叉树:[3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回其层次遍历结果:
[
[3],
[9,20],
[15,7]
]
//思路1BFS,优化广度遍历,一层一层放进deque进行遍历,遍历完一层就用list装完加入res
//思路2DFS,每一层递归都用index做标记
solution1 BFS 迭代
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
ArrayDeque<TreeNode> deque = new ArrayDeque<>();
if (root != null) {
deque.add(root);
}
while (!deque.isEmpty()){
int n = deque.size();
List<Integer> level = new ArrayList<>();
for (int i = 0;i<n;i++){
TreeNode node = deque.pop();
level.add(node.val);
if (node.left!=null){
deque.add(node.left);
}
if (node.right!=null){
deque.add(node.right);
}
}
res.add(level);
}
return res;
}
}
solution 2 DFS 递归
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null){
return res;
}
dfs(res,root,1);
return res;
}
public void dfs(List<List<Integer>> res,TreeNode node,int index){
if (res.size()<index){
res.add(new ArrayList<Integer>());
}
res.get(index-1).add(node.val);
if (node.left != null){
dfs(res,node.left,index+1);
}
if (node.right != null){
dfs(res,node.right,index+1);
}
}
}
200. 岛屿数量
给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:
[
['1','1','1','1','0'],
['1','1','0','1','0'],
['1','1','0','0','0'],
['0','0','0','0','0']
]
输出: 1
示例 2:
输入:
[
['1','1','0','0','0'],
['1','1','0','0','0'],
['0','0','1','0','0'],
['0','0','0','1','1']
]
输出: 3
解释: 每座岛屿只能由水平和/或竖直方向上相邻的陆地连接而成。
//思路1:用DFS把1以及周围的点变为0,用静态变量g保存grid,可以让不太的方法修改它
//思路2:用BFS将1以及周围变为0
solution1 DFS
class Solution {
char[][] g;
public int numIslands(char[][] grid) {
int res = 0;
g = grid;
int re = 0;
for (int i=0; i<g.length; i++){
for (int j=0; j < g[i].length; j++){
if (g[i][j] == '1') {
sink(i,j);
res ++;
}
}
}
return res;
}
public void sink(int i,int j){
//终止条件
if(i < 0 || j < 0 || i >= g.length || j >= g[0].length || g[i][j] == '0') return;
//当前层
g[i][j] = '0';
//下一层
sink(i + 1, j);
sink(i, j + 1);
sink(i - 1, j);
sink(i, j - 1);
}
}
solution2 BFS
class Solution {
char[][] g;
public int numIslands(char[][] grid) {
int res = 0;
g = grid;
for (int i=0; i<g.length; i++){
for (int j=0; j < g[i].length; j++){
if (g[i][j] == '1') {
bfs(i,j);
res ++;
}
}
}
return res;
}
public void bfs(int i,int j){
g[i][j] = '0';
int x = g.length;
int y=g[0].length;
int code = i*y + j;
ArrayDeque<Integer> deque = new ArrayDeque<>();
deque.push(code);
while(!deque.isEmpty()){
code = deque.pop();
int n = code/y;
int m = code%y;
if (n>0 && g[n-1][m] == '1'){
deque.push((n-1)*y+m);
g[n-1][m] = '0';
}
if (n<x-1 && g[n+1][m] == '1'){
deque.push((n+1)*y+m);
g[n+1][m] = '0';
}
if (m>0 && g[n][m-1] == '1'){
deque.push(n*y+(m-1));
g[n][m-1] = '0';
}
if (m<y-1 && g[n][m+1] == '1'){
deque.push(n*y+(m+1));
g[n][m+1] = '0';
}
}
}
}
111. 二叉树的最小深度
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回它的最小深度 2.
class Solution {
public int minDepth(TreeNode root) {
if (root == null) return 0;
Deque<TreeNode> dq = new LinkedList<>();
//往队列添加元素
dq.offer(root);
int depth = 1;
while( !dq.isEmpty()){
int len = dq.size();
//以当前队列中的所有节点向四周扩撒
for(int i = 0; i < len; i ++){
TreeNode node = dq.poll();
if(node.left == null && node.right == null){
return depth;
}
if (node.left != null){
dq.offer(node.left);
}
if (node.right != null){
dq.offer(node.right);
}
}
//增加深度
depth++;
}
return depth;
}
}
// 思路1: 运用BFS,以面单位进行搜索,使用dq进行保存
752. 打开转盘锁
你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有10个数字: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 。每个拨轮可以自由旋转:例如把 '9' 变为 '0','0' 变为 '9' 。每次旋转都只能旋转一个拨轮的一位数字。
锁的初始数字为 '0000' ,一个代表四个拨轮的数字的字符串。
列表 deadends 包含了一组死亡数字,一旦拨轮的数字和列表里的任何一个元素相同,这个锁将会被永久锁定,无法再被旋转。
字符串 target 代表可以解锁的数字,你需要给出最小的旋转次数,如果无论如何不能解锁,返回 -1。
示例 1:
输入:deadends = ["0201","0101","0102","1212","2002"], target = "0202"
输出:6
解释:
可能的移动序列为 "0000" -> "1000" -> "1100" -> "1200" -> "1201" -> "1202" -> "0202"。
注意 "0000" -> "0001" -> "0002" -> "0102" -> "0202" 这样的序列是不能解锁的,
因为当拨动到 "0102" 时这个锁就会被锁定。
示例 2:
输入: deadends = ["8888"], target = "0009"
输出:1
解释:
把最后一位反向旋转一次即可 "0000" -> "0009"。
示例 3:
输入: deadends = ["8887","8889","8878","8898","8788","8988","7888","9888"], target = "8888"
输出:-1
解释:
无法旋转到目标数字且不被锁定。
示例 4:
输入: deadends = ["0000"], target = "8888"
输出:-1
提示:
死亡列表 deadends 的长度范围为 [1, 500]。
目标数字 target 不会在 deadends 之中。
每个 deadends 和 target 中的字符串的数字会在 10,000 个可能的情况 '0000' 到 '9999' 中产生。
solution1
class Solution {
public int openLock(String[] deadends, String target) {
//死亡之组
Set<String> deads = new HashSet<String>();
for (String s:deadends){ deads.add(s);}
//遍历队列
Deque<String> dq = new LinkedList<String>();
//已遍历
Set<String> visited = new HashSet<String>();
//深度
int depth = 0;
dq.offer("0000");
visited.add("0000");
while(!dq.isEmpty()){
int sz = dq.size();
// 以面为单位遍历
for (int i = 0; i < sz; i++){
String curr = dq.poll();
if (deads.contains(curr)) continue;
if (curr.equals(target)) return depth; //不能用==
for (int j = 0; j < 4; j++){
String plus = plusOne(curr,j);
if (!visited.contains(plus)){
dq.offer(plus);
visited.add(plus);
}
String minus = minusOne(curr,j);
if (!visited.contains(minus)){
dq.offer(minus);
visited.add(minus);
}
}
}
depth++;
}
return -1;
}
// 目标转盘+1
private String plusOne(String s,int j){
char[] c = s.toCharArray();
if (c[j] == '9'){
c[j] = '0';
}else{
c[j]+=1;
}
return new String(c);
}
// 目标转盘-1
private String minusOne(String s,int j){
char[] c = s.toCharArray();
if (c[j] == '0'){
c[j] = '9';
}else{
c[j]-=1;
}
return new String(c);
}
}
//运用BFS,以“0000”为根,所有转动情况为根的子节点