Graph: Breadth First Search

126. Word Ladder II

Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) from beginWord to endWord, such that:

Only one letter can be changed at a time Each intermediate word must exist in the word list For example,

Given:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]
Return
  [
    ["hit","hot","dot","dog","cog"],
    ["hit","hot","lot","log","cog"]
  ]

Note: All words have the same length. All words contain only lowercase alphabetic characters.

class Solution {
public:
    vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {
        unordered_map<string, unordered_set<string>> traces;
        unordered_set<string> set1 {start};
        unordered_set<string> set2 {end};

        bfs_traces(set1, set2, dict, traces, false);
        vector<string> slu{start};
        vector<vector<string>> res;
        get_paths(traces, slu, res, start, end);
        return res;
    }

    void bfs_traces(unordered_set<string> set1, unordered_set<string> set2, unordered_set<string> &dict,
        unordered_map<string, unordered_set<string>>& traces, bool reversed) {

        if (set1.size() > set2.size()) return bfs_traces(set2, set1, dict, traces, !reversed);
        if (set1.size() == 0) return;

        for (auto word : set1) dict.erase(word);
        bool done = false;
        unordered_set<string> nextLevel;

        for (auto str : set1) {
            for (size_t i = 0; i < str.length(); ++i) {
                string next = str;
                for (char c = 'a'; c <= 'z'; ++c) {
                    next[i] = c;
                    if (str[i] == c || dict.find(next) == dict.end()) continue;

                    string key = reversed ? next : str;
                    string val = reversed ? str : next;

                    traces[key].insert(val);

                    if (set2.find(next) != set2.end()) {
                        done = true;
                    }
                    if (!done) nextLevel.insert(next);
                }
            }
        }

        if (!done) return bfs_traces(set2, nextLevel, dict, traces, !reversed);
    }

    void get_paths(unordered_map<string, unordered_set<string>>& traces, vector<string>& slu,
        vector<vector<string>>& res, string start, string end) {
        if (start == end) {
            res.push_back(slu);
            return;
        }
        for (auto word : traces[start]) {
            slu.push_back(word);
            get_paths(traces, slu, res, word, end);
            slu.pop_back();
        }
    }
};

130. Surrounded Regions

Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'.

A region is captured by flipping all 'O's into 'X's in that surrounded region.

For example,

X X X X
X O O X
X X O X
X O X X

After running your function, the board should be:

X X X X
X X X X
X X X X
X O X X

Show Tags Show Similar Problems

class Solution {
public:
    void solve(vector<vector<char>>& board) {
        if (!board.size() || !board[0].size()) return;
        int m = board.size();
        int n = board[0].size();
        queue<pair<int, int>> q;

        vector<vector<bool>> visited(m, vector<bool>(n, false));
        for (int i = 0; i < m; ++i) {
            if (board[i][0] == 'O') {
                visited[i][0] = true;
                q.push({i, 0});
            }
            if (n > 1 && board[i][n-1] == 'O') {
                visited[i][n-1] = true;
                q.push({i, n-1});
            }
        }

        for (int j = 0; j < n; ++j) {
            if (board[0][j] == 'O' && !visited[0][j]) {
                visited[0][j] = true;
                q.push({0,j});
            }
            if (m > 1 && board[m-1][j] == 'O' && !visited[m-1][j]) {
                visited[m-1][j] = true;
                q.push({m-1, j});
            }
        }
        vector<int> steps{0, 1, 0, -1, 0};
        while (!q.empty()) {
            auto cur = q.front(); q.pop();
            for (int i = 0; i < steps.size() - 1; ++i) {
                int x = cur.first + steps[i];
                int y = cur.second + steps[i+1];
                if (x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'O' && !visited[x][y]) {
                    q.push({x, y});
                    visited[x][y] = true;
                }
            }
        }

        for (size_t i = 0; i < m; ++i) {
            for (size_t j = 0; j < n; ++j) {
                if (board[i][j] == 'O' && !visited[i][j]) board[i][j] = 'X';
            }
        }
    }
};

97. Interleaving String

Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.

For example, Given: s1 = "aabcc", s2 = "dbbca",

When s3 = "aadbbcbcac", return true. When s3 = "aadbbbaccc", return false.

BFS 和 DFS 的解法都是4ms, DP的解法是12ms

class Solution {  // DP
public:
    bool isInterleave(string s1, string s2, string s3) {
        int len1 = s1.size();
        int len2 = s2.size();
        int len3 = s3.size();
        if (len1 + len2 != len3) return false;

        vector<vector<bool>> dp(len1+1, vector<bool>(len2+1, false));

        for (size_t i = 0; i <= len1; ++i) {
            for (size_t j = 0; j <= len2; ++j) {
                if (i == 0 && j == 0) dp[i][j] = true;
                else if (i == 0) {
                    dp[i][j] = dp[i][j-1] && (s3[i+j-1] == s2[j-1]);
                } else if (j == 0) {
                    dp[i][j] = dp[i-1][j] && (s3[i+j-1] == s1[i-1]);
                } else {
                    dp[i][j] = (dp[i][j-1] && (s3[i+j-1] == s2[j-1])) || (dp[i-1][j] && (s3[i+j-1] == s1[i-1])) ;
                }
            }
        }

        return dp[len1][len2];
    }
};
class Solution { // dfs
public:
    bool isInterleave(string s1, string s2, string s3) {
        int len1 = s1.size();
        int len2 = s2.size();
        int len3 = s3.size();
        if (len1 + len2 != len3) return false;
        vector<vector<bool>> isInvalid(len1 + 1, vector<bool>(len2 + 1, false));

        return dfs(s1, s2, s3, 0, 0, 0, isInvalid);
    }

    bool dfs(const string& s1, const string& s2, const string& s3, int i, int j, int k, vector<vector<bool>>& isInvalid) {
        if (isInvalid[i][j]) return false;
        if (k == s3.size()) return true;
        bool valid = (i < s1.size() && s1[i] == s3[k] && dfs(s1, s2, s3, i+1, j, k+1, isInvalid)) ||
                     (j < s2.size() && s2[j] == s3[k] && dfs(s1, s2, s3, i, j+1, k+1, isInvalid));
        isInvalid[i][j] = !valid;
        return valid;
    }
};
class Solution {  // bfs
public:
    bool isInterleave(string s1, string s2, string s3) {
        int len1 = s1.size();
        int len2 = s2.size();
        int len3 = s3.size();
        if (len1 + len2 != len3) return false;
        // unordered_set<int> visited;
        vector<vector<bool>> visited(len1 + 1, vector<bool>(len2 + 1, false));
        queue<pair<int, int>> q;
        q.push({-1, -1});

        while (!q.empty()) {
            auto cur = q.front(); q.pop();
            int i = cur.first + 1;
            int j = cur.second + 1;
            if (i == len1 && j == len2) return true;

            if (i + j < len3) {
                char next = s3[i+j];
                if (i < len1 && s1[i] == next) {
                    if (!visited[i+1][j]) {
                        q.push({i, j-1});
                        visited[i+1][j] = true;
                    }
                }
                if (j < len2 && s2[j] == next) {
                    if (!visited[i][j+1]) {
                        q.push({i-1, j});
                        visited[i][j+1] = true;
                    }
                }
            }
        }
        return false;
    }
};

279. Perfect Squares

Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...) which sum to n.

For example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9.

class Solution {
public:
    int numSquares(int n) {
        if (n <= 1) return n;
        vector<int> squares;
        vector<int> cnt(n+1);
        queue<int> q;
        for (int i = 1; i*i <= n; ++i) {
            squares.push_back(i*i);
            cnt[i*i] = 1;
            q.push(i*i);
        }
        if (squares.back() == n) return 1;

        int num = 1;
        while (!q.empty()) {
            num++;
            int len = q.size();
            while (len--) {
                int cur = q.front(); q.pop();
                for (auto j : squares) {
                    if (cur + j == n) {
                        return num;
                    } else if (cur + j < n && cnt[cur + j] == 0) {
                        cnt[cur + j] = num;
                        q.push(cur+j);
                    } else if (cur + j > n) break;
                }
            }
        }

        return 0;
    }
};

286 Walls and Gates

You are given a m x n 2D grid initialized with these three possible values.

-1 - A wall or an obstacle. 0 - A gate. INF - Infinity means an empty room. We use the value 231 - 1 = 2147483647 to represent INF as you may assume that the distance to a gate is less than 2147483647. Fill each empty room with the distance to its nearest gate. If it is impossible to reach a gate, it should be filled with INF.

For example, given the 2D grid:

INF  -1  0  INF
INF INF INF  -1
INF  -1 INF  -1
  0  -1 INF INF

After running your function, the 2D grid should be:

  3  -1   0   1
  2   2   1  -1
  1  -1   2  -1
  0  -1   3   4
class Solution {
public:
    void wallsAndGates(vector<vector<int>>& rooms) {
        size_t m = rooms.size();
        if (!m) return;
        size_t n = rooms[0].size();
        if (!n) return;
        queue<pair<pair<int, int>, int>> q;
        vector<vector<bool>> visited(rooms.size(), vector<bool>(rooms[0].size(), false));

        for (size_t i = 0; i < m; ++i) {
            for (size_t j = 0; j < n; ++j) {
               if (rooms[i][j]==0) {
                   q.push({{i,j},0});
               }
            }
        }

        while (!q.empty()) {
            int x_0 = q.front().first.first;
            int y_0 = q.front().first.second;
            int dist = q.front().second;
            visited[x_0][y_0] = true;
            q.pop();
            if (x_0 > 0
                && rooms[x_0-1][y_0] > 0) {
                if (rooms[x_0-1][y_0] > dist + 1) {
                    rooms[x_0-1][y_0] = dist + 1;
                    if (!visited[x_0-1][y_0])
                        q.push({{x_0-1, y_0}, rooms[x_0-1][y_0]});
                }
            }
            if (x_0 < rooms.size() - 1 && rooms[x_0+1][y_0] > 0) {
                if (rooms[x_0+1][y_0] > dist + 1) {
                    rooms[x_0+1][y_0] = dist + 1;
                    if (!visited[x_0+1][y_0])
                        q.push({{x_0+1, y_0}, rooms[x_0+1][y_0]});
                }
            }
            if (y_0 > 0 && rooms[x_0][y_0-1] > 0) {
                if (rooms[x_0][y_0-1] > dist + 1) {
                    rooms[x_0][y_0-1] = dist + 1;
                    if (!visited[x_0][y_0-1])
                        q.push({{x_0, y_0-1}, rooms[x_0][y_0-1]});
                }
            }
            if (y_0 < rooms[0].size() -1 && rooms[x_0][y_0+1] > 0) {
                if (rooms[x_0][y_0+1] > dist + 1) {
                    rooms[x_0][y_0+1] = dist + 1;
                    if (!visited[x_0][y_0+1])
                        q.push({{x_0, y_0+1}, rooms[x_0][y_0+1]});
                }
            }
        }
    }
};

301. Remove Invalid Parentheses

Remove the minimum number of invalid parentheses in order to make the input string valid. Return all possible results.

Note: The input string may contain letters other than the parentheses ( and ).

Examples: "()())()" -> ["()()()", "(())()"] "(a)())()" -> ["(a)()()", "(a())()"] ")(" -> [""]

class Solution {
public:
    vector<string> removeInvalidParentheses(string s) {
        vector<string> res;
        unordered_set<string> visited;
        if (isValid(s)) return {s};

        queue<string> q;
        q.push(s);
        visited.insert(s);
        bool found = false;
        while (!q.empty()) {
            auto str = q.front(); q.pop();

            if (isValid(str)) {
                found = true;
                res.push_back(str);
            }
            if (found) {
                continue;
            }

            for (size_t i = 0; i < str.size(); ++i) {
                if (str[i] != ')' && str[i] != '(') continue;
                string next = str.substr(0, i) + str.substr(i+1);
                if (visited.find(next) == visited.end()) {
                    q.push(next);
                    visited.insert(next);
                }
            }
        }
        return res;
    }

    bool isValid(const string& str) {
        int cnt = 0;
        for (auto ch : str) {
            if (ch == '(') cnt++;
            else if (ch == ')') {
                if (--cnt < 0) return false;
            }
        }
        return cnt == 0;
    }
};

310. Minimum Height Trees

For a undirected graph with tree characteristics, we can choose any node as the root. The result graph is then a rooted tree. Among all possible rooted trees, those with minimum height are called minimum height trees (MHTs). Given such a graph, write a function to find all the MHTs and return a list of their root labels.

Format The graph contains n nodes which are labeled from 0 to n - 1. You will be given the number n and a list of undirected edges (each edge is a pair of labels).

You can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges.

Example 1:

Given n = 4, edges = [[1, 0], [1, 2], [1, 3]]

        0
        |
        1
       / \
      2   3
return [1]

Example 2:

Given n = 6, edges = [[0, 3], [1, 3], [2, 3], [4, 3], [5, 4]]

     0  1  2
      \ | /
        3
        |
        4
        |
        5
return [3, 4]

Two solutions are the same, one is using indegree directly, the other using indegree implicitly

class Solution {
public:
    vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
        if (edges.size()==0)  return {0};
        vector<unordered_set<int>> graph(n);
        queue<int> q;
        // vector<int> degree(n);
        for (auto edge : edges) {
            // degree[edge.first]++;
            // degree[edge.second]++;
            graph[edge.first].insert(edge.second);
            graph[edge.second].insert(edge.first);
        }
        for (int i = 0;i < n; ++i)
            if (graph[i].size() == 1) q.push(i);

        vector<int> res;

        while (!q.empty()) {
            int cur_len = q.size();
            res.clear();
            while (cur_len--) {
                int v = q.front(); q.pop();
                res.push_back(v);
                for (auto w : graph[v]) {
                    graph[w].erase(v);
                    if (graph[w].size() == 1) q.push(w);
                }
            }
        }

        // while (!q.empty()) {
        //     int cur_len = q.size();
        //     res.clear();
        //     while (cur_len--) {
        //         int v = q.front(); q.pop();
        //         res.push_back(v);
        //         for (auto w :graph[v]) {
        //             if (--degree[w] == 1) q.push(w);
        //         }
        //     }
        // }
        return res;
    }
};

317 Shortest Distance from All Buildings

class Solution {
public:
    int shortestDistance(vector<vector<int>>& grid) {
        size_t m = grid.size();
        if (!m) return -1;
        size_t n = grid[0].size();
        if (!n) return -1;

        vector<vector<int>> dist(m, vector<int>(n, INT_MAX));
        vector<vector<int>> build_cnt(m, vector<int>(n, 0));
        vector<pair<size_t, size_t>> allBuildings;

        for (size_t i = 0; i < m; ++i) {
            for (size_t j = 0; j < n; ++j) {
                if (grid[i][j] == 1) allBuildings.push_back({i,j});
            }
        }

        for (auto building : allBuildings) {
            if (!bfs(grid, building.first, building.second, dist, build_cnt, allBuildings)) return -1;
        }
        int mindist = INT_MAX;
        for (size_t i = 0; i < m; ++i) {
            for (size_t j = 0; j < n; ++j) {
                if (grid[i][j] == 0 && build_cnt[i][j] == allBuildings.size()) {
                    mindist = min(mindist, dist[i][j]);
                }
            }
        }
        return mindist == INT_MAX ? -1 : mindist;

    }

    bool bfs(vector<vector<int>>& grid, size_t x, size_t y, vector<vector<int>>& dist, \
        vector<vector<int>>& build_cnt, vector<pair<size_t, size_t>>& allBuildings) {

        vector<vector<bool>> visited(grid.size(), vector<bool>(grid[0].size(), false));
        visited[x][y] = true;
        queue<pair<int, int>> q;
        q.push({x, y});
        int depth = 0;

        vector<int> delta{1, 0, -1, 0, 1};

        while (!q.empty()) {
            int len = q.size();
            while (len--) {
                auto cur = q.front();
                q.pop();
                int i = cur.first, j = cur.second;
                // cout << "visit : " << i << " ," << j << endl;
                dist[i][j] = dist[i][j] == INT_MAX ? depth : dist[i][j] + depth;
                build_cnt[i][j]++;
                for (int k = 0; k < delta.size() - 1; ++k) {
                    int m = i + delta[k];
                    int n = j + delta[k + 1];
                    if (m >= 0 && m < grid.size() && n >= 0 && n < grid[0].size() && !visited[m][n]) {
                        visited[m][n] = true;
                        if (grid[m][n] == 0) q.push({m, n});
                    }
                }
            }
            depth++;
        }

        for (auto building : allBuildings) {
            if (!visited[building.first][building.second]) {
                return false;
            }
        }
        return true;
    }
};

Rolling Ball Game

一个球从起点开始沿着通道,看能不能滚到终点。不过有限制, 每次球一走到底要不到边界,要不到障碍物,中间不能停留。 可以上下左右走,然后让写个function 给定起点, 终点,和图,判断是不是solvable. For example (1代表有障碍, 0代表可以通过):

results matching ""

    No results matching ""