搜索 (C++刷题笔记)

搜索 (C++刷题笔记)

200. 岛屿数量

力扣

DFS

  • 标记当前搜索位置已被搜索(标记当前位置的mark数组为1)

  • 按照四个方向扩展四个新位置newx,newy

  • 若新位置不在地图范围内,则忽略

  • 如果新位置未曾到达mark[new][newy],且是陆地,继续DFS该位置

void dfs(vector<vector<int> >&mark,vector<vector<char> >&grid,int x,int y){
    mark[x][y]=1;
    static const int dx[]={-1,1,0,0};
    static const int dy[]={0,0,-1,1};
    for (int i = 0; i < 4; ++i) {
        int nx=x+dx[i];
        int ny=y+dy[i];
        if(nx<0||nx>=grid.size()||ny<0||ny>=grid[0].size()){
            continue;
        }
        if(mark[nx][ny]==0&&grid[nx][ny]=='1'){
            dfs(mark,grid,nx,ny);
        }
    }

}

BFS

  • 设置搜索队列Q,标记mark[x][y]=1,并将待搜索位置(x,y)进入队列

  • 只要队列不为空,按照方向数组的四个方向,拓展四个新位置nx,ny

  • 若新位置不在地图范围内,则忽略

  • 如果新位置未曾到达过(mark[nx][ny]==0),且是陆地,将该新位置push进队列,并标记mark[nx][ny]=1

void bfs(vector<vector<int> > &mark, vector<vector<char> > &grid, int x, int y) {
    static const int dx[] = {-1, 1, 0, 0};
    static const int dy[] = {0, 0, -1, 1};
    queue<pair<int, int> > Q;
    Q.push(make_pair(x, y));
    mark[x][y] = 1;
    while (!Q.empty()) {
        x = Q.front().first;
        y = Q.front().second;
        Q.pop();
        for (int i = 0; i < 4; ++i) {
            int nx = x + dx[i];
            int ny = y + dy[i];
            if (nx < 0 || nx >= grid.size() || ny < 0 || ny >= grid[0].size()) {
                continue;
            }
            if (mark[nx][ny] == 0 && grid[nx][ny] == '1') {
                Q.push(make_pair(nx, ny));
                mark[nx][ny] = 1;
            }
        }

    }

}

算法思路

  • 设置初始岛屿数量为0

  • 设置mark数组,初始化

  • 遍历地图grid上所有点,如果是陆地,未被访问,调用搜索,搜索完成后一次,岛屿数量加一

题目代码

class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        int islandNum=0;
        vector<vector<int> >mark;
        for (int i = 0; i <grid.size() ; ++i) {
            mark.push_back(vector<int>());
            for (int j = 0; j <grid[0].size() ; ++j) {
                mark[i].push_back(0);
            }

        }
        for (int i = 0; i <grid.size() ; ++i) {
            for (int j = 0; j <grid[0].size() ; ++j) {
              if(mark[i][j]==0&&grid[i][j]=='1'){
                  dfs(mark,grid,i,j);
                  islandNum++;
              }
            }

        }
        return islandNum;

    }

    void dfs(vector<vector<int> > &mark, vector<vector<char> > &grid, int x, int y) {
        mark[x][y] = 1;
        static const int dx[] = {-1, 1, 0, 0};
        static const int dy[] = {0, 0, -1, 1};
        for (int i = 0; i < 4; ++i) {
            int nx = x + dx[i];
            int ny = y + dy[i];
            if (nx < 0 || nx >= grid.size() || ny < 0 || ny >= grid[0].size()) {
                continue;
            }
            if (mark[nx][ny] == 0 && grid[nx][ny] == '1') {
                dfs(mark, grid, nx, ny);
            }
        }

    }
};

void dfs(vector<vector<int> > &mark, vector<vector<char> > &grid, int x, int y) {
    mark[x][y] = 1;
    static const int dx[] = {-1, 1, 0, 0};
    static const int dy[] = {0, 0, -1, 1};
    for (int i = 0; i < 4; ++i) {
        int nx = x + dx[i];
        int ny = y + dy[i];
        if (nx < 0 || nx >= grid.size() || ny < 0 || ny >= grid[0].size()) {
            continue;
        }
        if (mark[nx][ny] == 0 && grid[nx][ny] == '1') {
            dfs(mark, grid, nx, ny);
        }
    }

}
class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        int islandNum=0;
        vector<vector<int> >mark;
        for (int i = 0; i <grid.size() ; ++i) {
            mark.push_back(vector<int>());
            for (int j = 0; j <grid[0].size() ; ++j) {
                mark[i].push_back(0);
            }

        }
        for (int i = 0; i <grid.size() ; ++i) {
            for (int j = 0; j <grid[0].size() ; ++j) {
              if(mark[i][j]==0&&grid[i][j]=='1'){
                  bfs(mark,grid,i,j);
                  islandNum++;
              }
            }

        }
        return islandNum;

    }

    void bfs(vector<vector<int> > &mark, vector<vector<char> > &grid, int x, int y) {
        static const int dx[] = {-1, 1, 0, 0};
        static const int dy[] = {0, 0, -1, 1};
        queue<pair<int, int> > Q;
        Q.push(make_pair(x, y));
        mark[x][y] = 1;
        while (!Q.empty()) {
            x = Q.front().first;
            y = Q.front().second;
            Q.pop();
            for (int i = 0; i < 4; ++i) {
                int nx = x + dx[i];
                int ny = y + dy[i];
                if (nx < 0 || nx >= grid.size() || ny < 0 || ny >= grid[0].size()) {
                    continue;
                }
                if (mark[nx][ny] == 0 && grid[nx][ny] == '1') {
                    Q.push(make_pair(nx, ny));
                    mark[nx][ny] = 1;
                }
            }

        }

    }


};

127. 单词接龙

力扣

使用map建图

bool connect(const string &s1,const string &s2){
    int cnt=0;
    for (int i = 0; i < s1.length(); ++i) {
        if(s1[i]!=s2[i]){
            cnt++;
        }
    }
    return cnt==1;
}

void constructGraph(string &beginWord,vector<string>&wordList,map<string,vector<string> >&graph){
    wordList.push_back(beginWord);
    for (int i = 0; i < wordList.size(); ++i){
        graph[wordList[i]]=vector<string >();
    }
    for (int i = 0; i <wordList.size() ; ++i) {
        for (int j = i+1; j <wordList.size() ; ++j) {
            if(connect(wordList[i],wordList[j])){
                graph[wordList[i]].push_back(wordList[j]);
                graph[wordList[j]].push_back(wordList[i]);
            }
        }
    }

}
  • 给定起点,终点,图,从起点开始,搜索过程中记录到达步数

  • 设置队列Q,队列节点pair<顶点,步数>;设置集合vis,记录搜索过的顶点;将<起点,1>添加到队列中

  • 队列不空,取出队列头部元素,若取出头部为终点单词,返回到达当前节点的步数;若不是,扩展该节点,将该节点的相邻且未添加到vis中的节点与步数同时添加到队列Q,并将扩展节点加入vis

  • 若最终无法搜索到终点单词,返回0

int bfs(string &beginWord, string &endWord, map<string, vector<string> > &graph) {
    queue<pair<string, int> > Q;
    set<string> vis;
    Q.push(make_pair(beginWord, 1));
    vis.insert(beginWord);
    while (!Q.empty()) {
        string node = Q.front().first;
        int step = Q.front().second;
        Q.pop();
        if (node == endWord) {
            return step;
        }
        vector<string> &neighbors = graph[node];
        for (int i = 0; i < neighbors.size(); ++i) {
            if (vis.find(neighbors[i]) == vis.end()) {
                Q.push(make_pair(neighbors[i], step + 1));
                vis.insert(neighbors[i]);
            }
        }

    }
    return 0;

}

题目代码

class Solution {
public:
    int ladderLength(string beginWord, string endWord, vector<string> &wordList) {
        map<string, vector<string> > graph;
        constructGraph(beginWord, wordList, graph);
        return bfs(beginWord, endWord, graph);

    }

    int bfs(string &beginWord, string &endWord, map<string, vector<string> > &graph) {
        queue<pair<string, int> > Q;
        set<string> vis;
        Q.push(make_pair(beginWord, 1));
        vis.insert(beginWord);
        while (!Q.empty()) {
            string node = Q.front().first;
            int step = Q.front().second;
            Q.pop();
            if (node == endWord) {
                return step;
            }
            vector<string> &neighbors = graph[node];
            for (int i = 0; i < neighbors.size(); ++i) {
                if (vis.find(neighbors[i]) == vis.end()) {
                    Q.push(make_pair(neighbors[i], step + 1));
                    vis.insert(neighbors[i]);
                }
            }

        }
        return 0;

    }

    bool connect(const string &s1, const string &s2) {
        int cnt = 0;
        for (int i = 0; i < s1.length(); ++i) {
            if (s1[i] != s2[i]) {
                cnt++;
            }
        }
        return cnt == 1;
    }

    void constructGraph(string &beginWord, vector<string> &wordList, map<string, vector<string> > &graph) {
        wordList.push_back(beginWord);
        for (int i = 0; i < wordList.size(); ++i) {
            graph[wordList[i]] = vector<string>();
        }
        for (int i = 0; i < wordList.size(); ++i) {
            for (int j = i + 1; j < wordList.size(); ++j) {
                if (connect(wordList[i], wordList[j])) {
                    graph[wordList[i]].push_back(wordList[j]);
                    graph[wordList[j]].push_back(wordList[i]);
                }
            }
        }

    }
};

126. 单词接龙 II

力扣

  • 宽度优先搜索,如何保存宽度优先搜索时的路径

  • 如果起点和终点之间有多条路径,如何将多条路径全部搜索出

  • 如果建立beginWord与wordList的连接时,若单词表中已经包含了beginword,按照127的方法建图,会出现什么问题

记录路径的BFS

  • 将普通队列更换为vector实现队列,保存所有搜索节点,pop节点时不会丢弃队头元素,只是移动front指针

  • 在队列节点中增加该节点的前驱节点下标,可通过下标寻找是队列的哪一个节点搜索到的当前的节点

struct Qitem {
    string node;
    int parent_pos;
    int step;

    Qitem(string node, int parent_pos, int step) :
            node(node), parent_pos(parent_pos), step(step) {}
};

多条路径的保存

到达某一位置存在多条路径,使用映射记录每个位置的最短需要的步数,新拓展到的位置只要未曾到达或者到达步数与最短步数相同,即将该位置添加到队列中,从而存储了从不同前驱到达该位置的情况。

建图的修改

由于wordList可能存在beginWord,直接将beginWord push进入wordList,可能会出现重复的结果

void constructGraph(string &beginWord, vector<string> &wordList, map<string, vector<string> > &graph) {
    int hasBeginWord = 0;
    for (int i = 0; i < wordList.size(); ++i) {
        if (wordList[i] == beginWord) {
            hasBeginWord = 1;
        }
        graph[wordList[i]] = vector<string>();
    }
    if (hasBeginWord == 0) {
        graph[beginWord] = vector<string>();
    }

    for (int i = 0; i < wordList.size(); ++i) {
        for (int j = i + 1; j < wordList.size(); ++j) {
            if (connect(wordList[i], wordList[j])) {
                graph[wordList[i]].push_back(wordList[j]);
                graph[wordList[j]].push_back(wordList[i]);
            }
        }
        if (hasBeginWord == 0 && connect(beginWord, wordList[i])) {
            graph[beginWord].push_back(wordList[i]);
        }
    }

}

BFS

  void bfs(string &beginWord, string &endWord, map<string, vector<string> > &graph,
             vector<Qitem> &Q, vector<int> &end_word_pos) {
        map<string, int> vis;
        int minStep = 0;
        Q.push_back(Qitem(beginWord, -1, 1));
        vis[beginWord] = 1;
        int front = 0;//队列头指向队列头
        while (front != Q.size()) {
            string &node = Q[front].node;
            int step = Q[front].step;
            if (minStep != 0 && step > minStep) {
                break;
            }
            if (node == endWord) {
                minStep = step;
                end_word_pos.push_back(front);
            }
            const vector<string> &neighbors = graph[node];
            for (int i = 0; i < neighbors.size(); ++i) {
                if (vis.find(neighbors[i]) == vis.end() || vis[neighbors[i]] == step + 1) {
                    Q.push_back(Qitem(neighbors[i], front, step + 1));
                    vis[neighbors[i]] = step + 1;
                }

            }
            front++;
        }


    }

题目代码

class Solution {
public:
    struct Qitem {
        string node;
        int parent_pos;
        int step;

        Qitem(string node, int parent_pos, int step) :
                node(node), parent_pos(parent_pos), step(step) {}
    };

    void bfs(string &beginWord, string &endWord, map<string, vector<string> > &graph,
             vector<Qitem> &Q, vector<int> &end_word_pos) {
        map<string, int> vis;
        int minStep = 0;
        Q.push_back(Qitem(beginWord, -1, 1));
        vis[beginWord] = 1;
        int front = 0;//队列头指向队列头
        while (front != Q.size()) {
            string &node = Q[front].node;
            int step = Q[front].step;
            if (minStep != 0 && step > minStep) {
                break;
            }
            if (node == endWord) {
                minStep = step;
                end_word_pos.push_back(front);
            }
            const vector<string> &neighbors = graph[node];
            for (int i = 0; i < neighbors.size(); ++i) {
                if (vis.find(neighbors[i]) == vis.end() || vis[neighbors[i]] == step + 1) {
                    Q.push_back(Qitem(neighbors[i], front, step + 1));
                    vis[neighbors[i]] = step + 1;
                }

            }
            front++;
        }


    }

    bool connect(const string &s1, const string &s2) {
        int cnt = 0;
        for (int i = 0; i < s1.length(); ++i) {
            if (s1[i] != s2[i]) {
                cnt++;
            }
        }
        return cnt == 1;
    }

    void constructGraph(string &beginWord, vector<string> &wordList, map<string, vector<string> > &graph) {
        int hasBeginWord = 0;
        for (int i = 0; i < wordList.size(); ++i) {
            if (wordList[i] == beginWord) {
                hasBeginWord = 1;
            }
            graph[wordList[i]] = vector<string>();
        }

        for (int i = 0; i < wordList.size(); ++i) {
            for (int j = i + 1; j < wordList.size(); ++j) {
                if (connect(wordList[i], wordList[j])) {
                    graph[wordList[i]].push_back(wordList[j]);
                    graph[wordList[j]].push_back(wordList[i]);
                }
            }
            if (hasBeginWord == 0 && connect(beginWord, wordList[i])) {
                graph[beginWord].push_back(wordList[i]);
            }
        }

    }
    vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
        map<string ,vector<string> >graph;
        constructGraph(beginWord,wordList,graph);
        vector<Qitem>Q;
        vector<int>end_word_pos;
        bfs(beginWord,endWord,graph,Q,end_word_pos);
        vector<vector<string> >res;
        for (int i = 0; i <end_word_pos.size() ; ++i) {
            int pos=end_word_pos[i];
            vector<string>path;
            while (pos!=-1){
                path.push_back(Q[pos].node);
                pos=Q[pos].parent_pos;
            }
            res.push_back(vector<string>());
            for (int j =path.size()-1; j >=0 ; --j) {
                res[i].push_back(path[j]);
            }
        }
        return res;

    }
};

到第32个样例过不去了,超时了,可以尝试去掉vis,或者把起点变成终点,终点变成起点,一次遍历直接放入res里

473. 火柴拼正方形

力扣

  • 想象正方形四条边为四个桶,将每个火柴杆回溯的放置在每个桶里,放置完n个火柴杆后,检查四个桶中的火柴杆长度和是否相同,相同返回真,不相同返回假

  • n个火柴杆综合对4取余为0,否则为假

  • 火柴杆从大到小排序,先尝试大的减少回溯可能

  • 每次,放置,每条边上不可能放置超过总和1/4长度的火柴杆

题目代码



class Solution {
public:
    bool makesquare(vector<int>& nums) {
        if(nums.size()<4){
            return false;
        }
        int sum=0;
        for (int i = 0; i < nums.size(); ++i){
            sum+=nums[i];
        }
        if(sum%4!=0){
            return false;
        }
        sort(nums.rbegin(),nums.rend());
        int bucket[4]={0};
        return dfs(0,nums,sum/4,bucket);

    }
    bool dfs(int i,vector<int>&nums,int target,int bucket[]){
        if(i>=nums.size()){
            return true;
        }
        for (int j = 0; j < 4; ++j) {
            bucket[j]+=nums[i];
            if(bucket[j]<=target&&dfs(i+1,nums,target,bucket)){
                return true;
            }
            bucket[j]-=nums[i];
        }
        return false;
    }
};

407. 接雨水 II

力扣

  • 能积水的底面一定不在四周,积水的多少与周围最矮的立方体有关

  • 围住中间积水的边界位置不一定在四周,所以找出四周最低点求直接差的点,不可行

  • 搜索队列使用优先级队列,越矮的点优先级越高,越优先进行搜索

  • 以矩形四周的点作为起始点进行广度优先搜索

  • 使用二维数组对push进入队列的点进行标记,搜索到该点后,不再push金队列中

  • 只要队列不为空,去除优先级队列队头元素进行搜索,按照上下左右四个方向进行拓展,忽略超出边界的点

  • 当对某点(x,y,h)进行扩展时新点(nx,nx,nh),如果h大于h[nx][ny]最终结果+=h-nh并将heightMap[nx][ny]赋值为h

  • (nx,ny,nh)进入优先队列并作标记

    struct Qitem{
        int x;
        int y;
        int h;
        Qitem(int x,int y,int h):x(x),y(y),h(h){}
    };
    struct cmp{
        bool operator()(const Qitem &a,const Qitem &b){
            return a.h>b.h;
        }
    };

题目代码

class Solution {
public:
    struct Qitem{
        int x;
        int y;
        int h;
        Qitem(int x,int y,int h):x(x),y(y),h(h){}
    };
    struct cmp{
        bool operator()(const Qitem &a,const Qitem &b){
            return a.h>b.h;
        }
    };
    int trapRainWater(vector<vector<int>>& heightMap) {
        priority_queue<Qitem,vector<Qitem>,cmp>Q;
        if(heightMap.size()<3||heightMap[0].size()<3){
            return 0;
        }
        int r=heightMap.size();
        int c=heightMap[0].size();
        vector<vector<int> >mark;
        for (int i = 0; i < r; ++i){
            mark.push_back(vector<int>());
            for (int j = 0; j < c; ++j) {
                mark[i].push_back(0);
            }
        }
        for (int i = 0; i < r; ++i){
            Q.push(Qitem(i,0,heightMap[i][0]));
            mark[i][0]=1;
            Q.push(Qitem(i,c-1,heightMap[i][c-1]));
            mark[i][c-1]=1;
        }
        for (int i = 1; i <c-1 ; ++i){
            Q.push(Qitem(0,i,heightMap[0][i]));
            mark[0][i]=1;
            Q.push(Qitem(r-1,i,heightMap[r-1][i]));
            mark[r-1][i]=1;
        }

        static const int dx[]={-1,1,0,0};
        static const int dy[]={0,0,-1,1};
        int res=0;
        while (!Q.empty()){
            int x=Q.top().x;
            int y=Q.top().y;
            int h=Q.top().h;
            Q.pop();
            for (int i = 0; i < 4; ++i){
                int nx=x+dx[i];
                int ny=y+dy[i];
                if(nx<0||nx>=r||ny<0||ny>=c||mark[nx][ny]==1){
                    continue;
                }
                if(h>heightMap[nx][ny]){
                    res+=h-heightMap[nx][ny];
                    heightMap[nx][ny]=h;

                }
                Q.push(Qitem(nx,ny,heightMap[nx][ny]));
                mark[nx][ny]=1;

            }
        }
        return res;
    }
};
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值