NEETCODE150 - Graph

9/5/2024

Number of Islands

class Solution {
  bool dfs(const vector<vector<char>> &grid, vector<vector<bool>> &visited, int i, int j) {
    if (i < 0 || i >= grid.size() || j < 0 || j >= grid[0].size()) return false;
    if (visited[i][j] || grid[i][j] == '0') return false;
    visited[i][j] = true;
    dfs(grid, visited, i + 1, j);
    dfs(grid, visited, i - 1, j);
    dfs(grid, visited, i, j - 1);
    dfs(grid, visited, i, j + 1);
    return true;
  }
public:
  int numIslands(vector<vector<char>>& grid) {
    vector<vector<bool>> visited(grid.size(), vector<bool>(grid[0].size(), false));
    int count = 0;
    for (int i = 0; i < grid.size(); ++i) {
      for (int j = 0; j < grid[0].size(); ++j) {
        if (dfs(grid, visited, i, j)) ++count;
      }
    }
    return count;
  }
};

Max Area of Island

class Solution {
  int dfs(const vector<vector<int>> &grid, vector<vector<char>> &visited, int i, int j) {
    if (i < 0 || i >= grid.size() || j < 0 || j >= grid[0].size()) return 0;
    if (visited[i][j] || grid[i][j] == 0) return 0;
    visited[i][j] = true;
    int area = 1 +
               dfs(grid, visited, i + 1, j) +
               dfs(grid, visited, i - 1, j) +
               dfs(grid, visited, i, j - 1) +
               dfs(grid, visited, i, j + 1);
    return area;
  }
public:
  int maxAreaOfIsland(vector<vector<int>>& grid) {
    vector<vector<char>> visited(grid.size(), vector<char>(grid[0].size(), false));
    int max_area = 0;
    for (int i = 0; i < grid.size(); ++i) {
      for (int j = 0; j < grid[0].size(); ++j) {
        max_area = max(max_area, dfs(grid, visited, i, j));
      }
    }
    return max_area;
  }
};

Clone Graph

/*
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> neighbors;
    Node() {
        val = 0;
        neighbors = vector<Node*>();
    }
    Node(int _val) {
        val = _val;
        neighbors = vector<Node*>();
    }
    Node(int _val, vector<Node*> _neighbors) {
        val = _val;
        neighbors = _neighbors;
    }
};
*/

class Solution {
  void dfs(Node *original, unordered_map<Node *, Node *> &clone) {
    Node *cloned_node = new Node(original->val);
    clone[original] = cloned_node;
    for (Node *n : original->neighbors) {
      if (clone.find(n) == clone.end()) dfs(n, clone);
      cloned_node->neighbors.push_back(clone[n]);
    }
  }

public:
  Node* cloneGraph(Node* node) {
    if (!node) return nullptr;
    unordered_map<Node *, Node *> clone;
    dfs(node, clone);
    return clone[node];
  }
};

Islands and Treasure (Walls and Gates)

比较有意思的一点,先把所有的位置加到队列里,由于使用了 BFS ,只要该位置的距离被更新过了,那么这个距离一定比现在的距离更短,相应的后续节点也不用遍历了。

const int INF = 2147483647;

class Solution {
  struct State { int i, j, d; };
public:
  void islandsAndTreasure(vector<vector<int>>& grid) {
    queue<State> pending;

    for (int i = 0; i < grid.size(); ++i) {
      for (int j = 0; j < grid[0].size(); ++j) {
        if (grid[i][j] == 0) pending.push({i, j, 0});
      }
    }

    while (!pending.empty()) {
      auto s = pending.front();
      pending.pop();

      if (s.i < 0 || s.j < 0 || s.i >= grid.size() || s.j >= grid[0].size()) continue;
      if (grid[s.i][s.j] != INF && grid[s.i][s.j] != 0) continue;
      if (grid[s.i][s.j] != 0) grid[s.i][s.j] = s.d;

      pending.push({s.i, s.j + 1, s.d + 1});
      pending.push({s.i, s.j - 1, s.d + 1});
      pending.push({s.i + 1, s.j, s.d + 1});
      pending.push({s.i - 1, s.j, s.d + 1});
    }
  }
};

Rotting Oranges

注意判断状态是否有效的时机。在将状态加入队列时判断?还是取出状态时判断

class Solution {
public:
  struct State { int i, j; };
  int orangesRotting(vector<vector<int>>& grid) {
    int count = 0;
    queue<State> pending;
    for (int i = 0; i < grid.size(); ++i) {
      for (int j = 0; j < grid[0].size(); ++j) {
        if (grid[i][j] == 2) pending.push({i, j});
        if (grid[i][j] == 1) ++count;
      }
    }

    vector<pair<int, int>> didj = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    int time = 0;
    while (!pending.empty() && count > 0) {
      int current_size = pending.size();
      for (int i = 0; i < current_size; ++i) {
        auto s = pending.front();
        pending.pop();
        for (auto [di, dj] : didj) {
          int ni = s.i + di, nj = s.j + dj;
          if (ni < 0 || nj < 0 || ni >= grid.size() || nj >= grid[0].size()) continue;
          if (grid[ni][nj] == 1) {
            grid[ni][nj] = 2;
            --count;
            pending.push({ni, nj});
          }
        }
      }
      ++time;
    }
    return count == 0 ? time : -1;
  }
};

Pacific Atlantic Water Flow

反向思考有时更加高效

class Solution {
public:
  vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {
    vector<vector<char>> pacific(heights.size(), vector<char>(heights[0].size(), false));
    vector<vector<char>> atlantic(heights.size(), vector<char>(heights[0].size(), false));
    vector<vector<int>> res;
    for (int i = 0; i < heights.size(); ++i)
      dfs(heights, pacific, i, 0), dfs(heights, atlantic, i, heights[0].size() - 1);
    for (int j = 0; j < heights[0].size(); ++j)
      dfs(heights, pacific, 0, j), dfs(heights, atlantic, heights.size() - 1, j);
    for (int i = 0; i < heights.size(); ++i)
      for (int j = 0; j < heights[0].size(); ++j)
        if (pacific[i][j] && atlantic[i][j]) res.push_back({i, j});
    return res;
  }

  void dfs(const vector<vector<int>> &grid, vector<vector<char>> &connect, int i, int j) {
    connect[i][j] = true;
    vector<pair<int, int>> didjs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    for (auto [di, dj] : didjs) {
      int ni = i + di, nj = j + dj;
      if (ni >= 0 && nj >= 0 &&
          ni < grid.size() && nj < grid[0].size() &&
          !connect[ni][nj] &&
          grid[ni][nj] >= grid[i][j]) {
        connect[ni][nj] = true;
        dfs(grid, connect, ni, nj);
      }
    }
  }
};

Wrong Answer

class Solution {
public:
  vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {
    vector<vector<char>> pacific(heights.size(), vector<char>(heights[0].size(), false));
    for (int i = 0; i < heights.size(); ++i) pacific[i][0] = true;
    for (int j = 0; j < heights[0].size(); ++j) pacific[0][j] = true;
    for (int i = 1; i < heights.size(); ++i) {
      for (int j = 1; j < heights[0].size(); ++j) {
        pacific[i][j] = (heights[i - 1][j] <= heights[i][j] && pacific[i - 1][j]) ||
                        (heights[i][j - 1] <= heights[i][j] && pacific[i][j - 1]);
      }
    }

    vector<vector<char>> atlantic(heights.size(), vector<char>(heights[0].size(), false));
    for (int i = 0; i < heights.size(); ++i) atlantic[i][heights[0].size() - 1] = true;
    for (int j = 0; j < heights[0].size(); ++j) atlantic[heights.size() - 1][j] = true;
    for (int i = heights.size() - 2; i >= 0; --i) {
      for (int j = heights[0].size() - 2; j >= 0; --j) {
        atlantic[i][j] = (heights[i + 1][j] <= heights[i][j] && atlantic[i + 1][j]) ||
                         (heights[i][j + 1] <= heights[i][j] && atlantic[j][j + 1]);
      }
    }

    vector<vector<int>> res;
    for (int i = 0; i < heights.size(); ++i) {
      for (int j = 0; j < heights[0].size(); ++j) {
        if (pacific[i][j] && atlantic[i][j]) res.push_back({i, j});
      }
    }
    return res;
  }
};
1 2 3
8 9 4
7 5 6

Surrounded Regions

反向思考 + 1

class Solution {
public:
  void solve(vector<vector<char>>& board) {
    vector<vector<char>> safe(board.size(), vector<char>(board[0].size(), false));
    for (int i = 0; i < board.size(); ++i) dfs(board, i, (int)board[0].size() - 1, safe), dfs(board, i, 0, safe);
    for (int j = 0; j < board[0].size(); ++j) dfs(board, 0, j, safe), dfs(board, board.size() - 1, j, safe);
    for (int i = 0; i < board.size(); ++i)
      for (int j = 0; j < board[0].size(); ++j)
        if (!safe[i][j]) board[i][j] = 'X';
    }

    void dfs(const vector<vector<char>>& board, int i, int j, vector<vector<char>>& safe) {
      if (i < 0 || j < 0 || i >= board.size() || j >= board[0].size() || board[i][j] == 'X' || safe[i][j]) return;
      safe[i][j] = true;
      vector<pair<int, int>> didjs = { {1, 0}, {-1, 0}, {0, 1}, {0, -1} };
      for (auto [di, dj] : didjs) dfs(board, i + di, j + dj, safe);
    }
};