面试题_DFS
200. 岛屿数量
给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:grid = [
["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
输出:1
示例 2:
输入:grid = [
["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
输出:3
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 300
grid[i][j] 的值为 '0' 或 '1'
法一:深度优先搜索
class Solution:
def __init__(self):
self.dirs = [[-1, 0], [1, 0], [0, -1], [0, 1]]
def dfs(self, grid, r, c, row, col):
grid[r][c] = '0';
if r - 1 >= 0 and grid[r-1][c] == '1':
self.dfs(grid, r - 1, c, row, col)
if r + 1 < row and grid[r+1][c] == '1':
self.dfs(grid, r + 1, c, row, col)
if c - 1 >= 0 and grid[r][c-1] == '1':
self.dfs(grid, r, c - 1, row, col)
if c + 1 < col and grid[r][c+1] == '1':
self.dfs(grid, r, c + 1, row, col)
def numIslands(self, grid: List[List[str]]) -> int:
row, col = len(grid), len(grid[0])
ans = 0
for i in range(row):
for j in range(col):
if grid[i][j] == '1':
ans += 1
self.dfs(grid, i, j, row, col)
return ans
时间复杂度:O(MN)
空间复杂度:O(MN)
法二:广度优先搜索
class Solution:
def numIslands(self, grid):
row = len(grid)
if row == 0:
return 0
col = len(grid[0])
ans = 0
for r in range(row):
for c in range(col):
if grid[r][c] == '1':
ans += 1
grid[r][c] = '0'
neighbors = collections.deque([(r, c)])
while neighbors:
nr, nc = neighbors.popleft()
for x, y in [(nr - 1, nc), (nr + 1, nc), (nr, nc - 1), (nr, nc + 1)]:
if 0 <= x < row and 0 <= y < col and grid[x][y] == '1':
neighbors.append((x, y))
grid[x][y] = '0'
return ans
695. 岛屿的最大面积
给你一个大小为 m x n 的二进制矩阵 grid 。岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。岛屿的面积是岛上值为 1 的单元格的数目。计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。
示例 1:
输入:grid = [[0,0,1,0,0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,1,1,0,1,0,0,0,0,0,0,0,0],[0,1,0,0,1,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,0,0,0,0]]
输出:6
解释:答案不应该是 11 ,因为岛屿只能包含水平或垂直这四个方向上的 1 。
示例 2:
输入:grid = [[0,0,0,0,0,0,0,0]]
输出:0
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 50
grid[i][j] 为 0 或 1695. 岛屿的最大面积
给你一个大小为 m x n 的二进制矩阵 grid 。
岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。
岛屿的面积是岛上值为 1 的单元格的数目。计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。
示例 1:
输入:grid = [[0,0,1,0,0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,1,1,0,1,0,0,0,0,0,0,0,0],[0,1,0,0,1,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,0,0,0,0]]
输出:6
解释:答案不应该是 11 ,因为岛屿只能包含水平或垂直这四个方向上的 1 。
示例 2:
输入:grid = [[0,0,0,0,0,0,0,0]]
输出:0
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 50
grid[i][j] 为 0 或 1
class Solution:
def __init__(self):
self.num = 0
def dfs(self, grid, r, c, row, col):
grid[r][c] = 0
dirs = [[-1, 0], [1, 0], [0, -1], [0, 1]]
for d in range(4):
nr, nc = r + dirs[d][0], c + dirs[d][1]
if 0 <= nr < row and 0 <= nc < col and grid[nr][nc] == 1:
self.num += 1
self.dfs(grid, nr, nc, row, col)
return self.num
def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
row = len(grid)
if row == 0:
return 0
col = len(grid[0])
ans = 0
for r in range(row):
for c in range(col):
if grid[r][c] == 1:
self.num = 1
ans = max(ans, self.dfs(grid, r, c, row, col))
return ans
法二:广度优先搜索
class Solution:
def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
row = len(grid)
if row == 0:
return 0
col = len(grid[0])
ans = 0
for r in range(row):
for c in range(col):
if grid[r][c] == 1:
cur = 1
grid[r][c] = 0
q = collections.deque([(r, c)])
while q:
nr, nc = q.popleft()
for x, y in [(nr - 1, nc), (nr + 1, nc), (nr, nc - 1), (nr, nc + 1)]:
if 0 <= x < row and 0 <= y < col and grid[x][y] == 1:
q.append((x, y))
grid[x][y] = 0
cur += 1
ans = max(ans, cur)
return ans
剑指 Offer 13. 机器人的运动范围
地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
示例 1:
输入:m = 2, n = 3, k = 1
输出:3
示例 2:
输入:m = 3, n = 1, k = 0
输出:1
提示:
1 <= n,m <= 100
0 <= k <= 20
法一:DFS
class Solution:
def __init__(self):
self.ans = 0
def calcNum(self, num):
ans = 0
while num:
ans += num % 10
num //= 10
return ans
def dfs(self, i, j, m, n, k, vis):
if i >= m or j >= n or vis[i][j] or self.calcNum(i) + self.calcNum(j) > k:
return 0
vis[i][j] = 1
return 1 + self.dfs(i + 1, j, m, n, k, vis) + self.dfs(i, j + 1, m, n, k, vis)
def movingCount(self, m: int, n: int, k: int) -> int:
vis = [[0]*n for _ in range(m)]
return self.dfs(0, 0, m, n, k, vis)
法二:BFS
class Solution {
public:
int digitSum(int num)
{
// int ans = 0;
// while(num)
// {
// ans += num % 10;
// num /= 10;
// }
// return ans;
return num >= 10 ? num / 10 + num % 10 : num;
}
int movingCount(int m, int n, int k) {
vector<vector<bool> > vis(m, vector<bool>(n, 0));
int res = 0;
queue<vector<int> > que;
que.push({0, 0});
while (!que.empty())
{
vector<int> x = que.front(); que.pop();
int i = x[0], j = x[1];
if (i >= m || j >= n || digitSum(i) + digitSum(j) > k || vis[i][j]) {
continue;
}
vis[i][j] = true;
res++;
que.push({i + 1, j});
que.push({i, j + 1});
}
return res;
}
};
剑指 Offer 12. 矩阵中的路径
给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。例如,在下面的 3×4 的矩阵中包含单词 "ABCCED"(单词中的字母已标出)。
示例 1:
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true
示例 2:
输入:board = [["a","b"],["c","d"]], word = "abcd"
输出:false
提示:
1 <= board.length <= 200
1 <= board[i].length <= 200
board 和 word 仅由大小写英文字母组成
class Solution:
def dfs(self, board, i, j, row, col, word, k, wlen):
if (not (0 <= i < row)) or (not (0 <= j < col)) or board[i][j] != word[k]:
return False
if k == wlen - 1: return True
board[i][j] = ''
res = self.dfs(board, i + 1, j, row, col, word, k + 1, wlen) or \
self.dfs(board, i - 1, j, row, col, word, k + 1, wlen) or \
self.dfs(board, i, j + 1, row, col, word, k + 1, wlen) or \
self.dfs(board, i, j - 1, row, col, word, k + 1, wlen)
board[i][j] = word[k]
return res
def exist(self, board: List[List[str]], word: str) -> bool:
row, col = len(board), len(board[0])
wlen = len(word)
for i in range(row):
for j in range(col):
if self.dfs(board, i, j, row, col, word, 0, wlen):
return True
return False
class Solution {
public:
bool dfs(vector<vector<char>>& board, int i, int j, int row, int col, string word, int k, int wlen)
{
if (i >= row || i < 0 || j >= col || j < 0 || board[i][j] != word[k]) {
return false;
}
if (k == wlen - 1) return true;
board[i][j] = '\0';
bool res = dfs(board, i + 1, j, row, col, word, k + 1, wlen) ||
dfs(board, i - 1, j, row, col, word, k + 1, wlen) ||
dfs(board, i, j + 1, row, col, word, k + 1, wlen) ||
dfs(board, i, j - 1, row, col, word, k + 1, wlen);
board[i][j] = word[k];
return res;
}
bool exist(vector<vector<char>>& board, string word) {
int row = board.size(), col = board[0].size();
int wlen = word.length();
for(int i = 0; i < row; i++)
{
for(int j = 0; j < col; j++)
{
if (dfs(board, i, j, row, col, word, 0, wlen)) {
return true;
}
}
}
return false;
}
};
113. 路径总和 II
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。
示例 1:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]
示例 2:
输入:root = [1,2,3], targetSum = 5
输出:[]
示例 3:
输入:root = [1,2], targetSum = 0
输出:[]
提示:
树中节点总数在范围 [0, 5000] 内
-1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
vector<vector<int> > ans;
public:
void dfs(TreeNode* root, vector<int>& track, int targetSum)
{
if (root == nullptr) {
return;
}
track.emplace_back(root->val);
targetSum -= root->val;
if (root->left == nullptr && root->right == nullptr && targetSum == 0) {
ans.emplace_back(track);
}
dfs(root->left, track, targetSum);
dfs(root->right, track, targetSum);
track.pop_back();
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
if (root == nullptr) {
return {};
}
vector<int> track;
dfs(root, track, targetSum);
return ans;
}
};
时间复杂度:O(n2);空间复杂度:O(n)
法二:bfs
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
vector<vector<int> > ans;
unordered_map<TreeNode*, TreeNode*> parent;
public:
void getPath(TreeNode* node)
{
vector<int> tmp;
while (node != nullptr) {
tmp.emplace_back(node->val);
node = parent[node];
}
reverse(tmp.begin(), tmp.end());
ans.emplace_back(tmp);
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum)
{
if (root == nullptr) {
return ans;
}
queue<TreeNode*> que_node;
queue<int> que_sum;
que_node.emplace(root);
que_sum.emplace(0);
while (!que_node.empty())
{
TreeNode* node = que_node.front(); que_node.pop();
int res = que_sum.front() + node->val; que_sum.pop();
if (node->left == nullptr && node->right == nullptr) {
if (res == targetSum) {
getPath(node);
}
} else {
if (node->left) {
parent[node->left] = node;
que_node.emplace(node->left);
que_sum.emplace(res);
}
if (node->right) {
parent[node->right] = node;
que_node.emplace(node->right);
que_sum.emplace(res);
}
}
}
return ans;
}
};