Leetcode ブラッシング ノート (C++) - 深い検索全体の検索

Leetcode ブラッシング ノート (C++) - 深い検索全体の検索

質問をブラッシュアップする過程でアイデアを整理し、ここにまとめて共有します。
github アドレス: https://github.com/lvjian0706/Leetcode-solutions
github プロジェクトは新しく作成されたばかりで、C++ と Python をベースに整理されたコードやアイデアが次々とアップロードされます。同時に、基本的な並べ替えアルゴリズムも並べ替えてアップロードされます。

133. クローンマップ

無向接続グラフ内のノードへの参照が与えられると、そのグラフのディープ コピー (クローン) を返すように求められます。

グラフ内の各ノードには、その値 val (int) とその隣接ノードのリスト (list[Node]) が含まれます。

クラスノード { public int val; パブリック 近隣リストをリストします。}


テストケースの形式:

簡単にするために、各ノードの値はそのインデックスと同じです。たとえば、最初のノードの値は 1 (val = 1)、2 番目のノードの値は 2 (val = 2) などとなります。テスト ケースでは、グラフは隣接リストを使用して表されます。

隣接リストは、有限グラフを表すために使用される順序なしリストのコレクションです。各リストは、グラフ内のノードの近傍のセットを記述します。

指定されたノードは常にグラフ内の最初のノードになります (値は 1)。指定されたノードのコピーを、複製されたグラフへの参照として返す必要があります。

/*
// 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 {
    
    
public:
    /*
    使用哈希表visited进行深度遍历,深度遍历实际上就是递归遍历图中节点:
    1. 当遍历到的节点为空时,返回NULL;
    2. 当遍历到的节点已被访问过,直接返回使用该节点创建的新节点;
    3. 否则,使用该节点创建新节点,并在visited中进行标记:
    3.1 新节点的值为原始节点的值;
    3.2 新节点的邻接列表为与原始节点的邻接列表中的节点一一对应的新节点,在对应过程中,如果不存在该节点,递归调用DFS进行创建,如果存在,则为情况2,直接返回该新节点;
    */
    Node* DFS(Node* node, map<Node*, Node*> &visited){
    
    
        if(!node) return NULL;
        /*
        count()为在哈希表中统计个数的方法,可用于判断是否存在该键
        */
        if(visited.count(node)) return visited[node];
        Node* new_node = new Node(node->val);
        visited[node] = new_node;
        for(int i=0; i<node->neighbors.size(); i++){
    
    
            new_node->neighbors.push_back(DFS(node->neighbors[i], visited));
        }
        return new_node;
    }

    /*
    图的克隆过程其实就是图的遍历过程,因此可以使用DFS或BFS,又因为图为无向连通图,为了避免重复遍历节点,使用哈希表记录已访问节点;
    由于是做深拷贝,所以哈希表中键值对分别为原节点:新节点,用于返回新节点;
    */
    Node* cloneGraph(Node* node) {
    
    
        map<Node*, Node*> visited;
        return DFS(node, visited);
    }
};


/*
// 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 {
    
    
public:
    /*
    使用哈希表visited进行广度遍历:
    1. 当节点为空时,返回NULL;
    2. 定义队列用来存储当前访问的节点,并将当前节点push进队列中;
    3. 将当前节点作为键,使用当前节点创建的新节点作为值存入visited(新节点的邻接列表先不管);
    4. 当队列不为空时,循环遍历队列中的节点:
    4.1 取出队头元素,循环遍历队头结点的邻接节点:
    4.1.1 当节点没有访问过时,创建新节点,将原节点push到队列中,并在visited中进行标记;(由于是先创建后标记,所以可以保证visited中的每一个键节点对应的值节点都已经被创建过)
    4.1.2 将队头结点对应的新节点的邻接节点赋值为队头结点的邻接节点对应的新节点;
    */
    Node* DFS(Node* node, map<Node*, Node*> &visited){
    
    
        if(!node) return NULL;
        queue<Node*> nodeQ;
        nodeQ.push(node);
        Node* new_node = new Node(node->val);
        visited[node] = new_node;
        while(!nodeQ.empty()){
    
    
            Node* temp = nodeQ.front();
            nodeQ.pop();
            for(int i=0; i<temp->neighbors.size(); i++){
    
    
                if(!visited.count(temp->neighbors[i])){
    
    
                    Node* new_temp = new Node(temp->neighbors[i]->val);
                    visited[temp->neighbors[i]] = new_temp;
                    nodeQ.push(temp->neighbors[i]);
                }
                visited[temp]->neighbors.push_back(visited[temp->neighbors[i]]);
            }
        }
        return new_node;
    }

    /*
    图的克隆过程其实就是图的遍历过程,因此可以使用DFS或BFS,又因为图为无向连通图,为了避免重复遍历节点,使用哈希表记录已访问节点;
    由于是做深拷贝,所以哈希表中键值对分别为原节点:新节点,用于返回新节点;
    */
    Node* cloneGraph(Node* node) {
    
    
        map<Node*, Node*> visited;
        return DFS(node, visited);
    }
};

200. 島の数

「1」(陸地) と「0」(水域) で構成される 2D グリッドがある場合、グリッド内の島の数を数えてください。

島は常に水に囲まれており、各島は水平または垂直に隣接する土地を結合することによってのみ形成されます。

また、メッシュの四方すべてが水で囲まれていると考えることができます。

例 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
説明: 各アイランドのみが可能隣接するランドを水平および/または垂直に接続することによって形成される。

class Solution {
    
    
public:
    /*
    深度遍历grid:
    1. 定义坐标偏移量dx,dy,在遍历过程中,使用x+dx,y+dy来定义四个方向的相邻位置;
    2. 将visited中此时遍历到的位置赋为1;
    3. 循环遍历相邻的4个位置,当相邻点为1且visited中对应点为0时,可以从该相邻点继续进行递归遍历;
    */
    void DFS(vector<vector<char>>& grid, vector<vector<int>> &visited, int x, int y){
    
    
        vector<int> dx = {
    
    0, 0, -1, 1};
        vector<int> dy = {
    
    -1, 1, 0, 0};
        visited[x][y] = 1;
        for(int i=0; i<4; i++){
    
    
            int new_x = x + dx[i];
            int new_y = y + dy[i];
            /*
            判断是否越界
            */
            if(new_x >= 0 && new_x <= grid.size()-1 && new_y >= 0 && new_y <= grid[0].size()-1){
    
    
                if(grid[new_x][new_y]=='1' && visited[new_x][new_y]==0){
    
    
                    DFS(grid, visited, new_x, new_y);
                }
            }
        }
    }

    /*
    统计网格中岛屿的数量:图的遍历问题,可以使用DFS和BFS,其中,为了避免重复遍历问题,定义visited数组记录遍历过的位置,遍历过将该位置赋为1,没有遍历过为0;
    循环遍历grid,当该点为1且visited中对应点为0时,岛屿数量加1,同时进入DFS或BFS,把相通的点都遍历到,visited对应位置修改为1;
    */
    int numIslands(vector<vector<char>>& grid) {
    
    
        if(grid.size()==0 || grid[0].size()==0) return 0;
        int m = grid.size(), n = grid[0].size();
        vector<vector<int>> visited(m, vector<int>(n));
        for(int i=0; i<m; i++){
    
    
            for(int j=0; j<n; j++){
    
    
                visited[i][j] = 0;
            }
        }
        int num = 0;
        for(int i=0; i<m; i++){
    
    
            for(int j=0; j<n; j++){
    
    
                if(grid[i][j]=='1' && visited[i][j]==0){
    
    
                    num++;
                    DFS(grid, visited, i, j);
                }
            }
        }
        return num;
    }
};


class Solution {
    
    
public:
    /*
    广度遍历grid:
    1. 定义坐标偏移量dx,dy,在遍历过程中,使用x+dx,y+dy来定义四个方向的相邻位置;
    2. 定义队列存放访问到的grid为1的x,y值,将初始的x,y入队列,同时将visited[x][y]赋为1;
    3. 当队列不为空时,循环遍历队列:
    3.1 取出队头的x,y,循环遍历4个方向的相邻元素,如果该相邻点为1且visited中对应点为0时,将该相邻点位置入队列,同时将visited[new_x][new_y]赋为1;
    */
    void BFS(vector<vector<char>>& grid, vector<vector<int>> &visited, int x, int y){
    
    
        vector<int> dx = {
    
    0, 0, -1, 1};
        vector<int> dy = {
    
    -1, 1, 0, 0};
        visited[x][y] = 1;
        queue<pair<int, int>> island;
        island.push(make_pair(x, y));
        while(!island.empty()){
    
    
            int old_x = island.front().first;
            int old_y = island.front().second;
            island.pop();
            for(int i=0; i<4; i++){
    
    
                int new_x = old_x + dx[i];
                int new_y = old_y + dy[i];
                if(new_x >= 0 && new_x < grid.size() && new_y >= 0 && new_y < grid[0].size()){
    
    
                    if(grid[new_x][new_y]=='1' && visited[new_x][new_y]==0){
    
    
                        island.push(make_pair(new_x, new_y));
                        visited[new_x][new_y] = 1;
                    }
                }
            }
        }
    }

    /*
    统计网格中岛屿的数量:图的遍历问题,可以使用DFS和BFS,其中,为了避免重复遍历问题,定义visited数组记录遍历过的位置,遍历过将该位置赋为1,没有遍历过为0;
    循环遍历grid,当该点为1且visited中对应点为0时,岛屿数量加1,同时进入DFS或BFS,把相通的点都遍历到,visited对应位置修改为1;
    */
    int numIslands(vector<vector<char>>& grid) {
    
    
        if(grid.size()==0 || grid[0].size()==0) return 0;
        int m = grid.size(), n = grid[0].size();
        vector<vector<int>> visited(m, vector<int>(n));
        for(int i=0; i<m; i++){
    
    
            for(int j=0; j<n; j++){
    
    
                visited[i][j] = 0;
            }
        }
        int num = 0;
        for(int i=0; i<m; i++){
    
    
            for(int j=0; j<n; j++){
    
    
                if(grid[i][j]=='1' && visited[i][j]==0){
    
    
                    num++;
                    BFS(grid, visited, i, j);
                }
            }
        }
        return num;
    }
};

おすすめ

転載: blog.csdn.net/weixin_43273742/article/details/107740799