面试题_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(n^2)\);空间复杂度: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;
    }

};

posted @ 2022-06-13 23:05  douzujun  阅读(17)  评论(0编辑  收藏  举报