数据结构与算法——搜索

1.内容概述

在这里插入图片描述

2.岛屿数量

2.1 题目描述

给你一个由 ‘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

2.2 DFS深度搜索算法思路

在这里插入图片描述
在这里插入图片描述

#include<iostream>
#include<vector>
using namespace std;

void DFS(vector<vector<int>>& mark, vector<vector<char>>& grid, int x, int y) {
    mark[x][y] = 1;

    int dx[] = { -1,1,0,0 };
    int dy[] = { 0,0,-1,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_y < 0 || new_x >= mark.size() || new_y >= mark[new_x].size()) {
            continue;
        }
        if (mark[new_x][new_y] == 0 && grid[new_x][new_y] == '1') {
            DFS(mark, grid, new_x, new_y);
        }
    }
}

int main()
{
    vector<vector<char>> grid = { {'1','1','1','0','0'},
                                  {'1','1','0','0','0'},
                                  {'0','0','1','0','0'},
                                  {'0','0','0','1','1'} 
                                };
    vector<vector<int>> mark = { {0,0,0,0,0},
                                 {0,0,0,0,0},
                                 {0,0,0,0,0},
                                 {0,0,0,0,0},
    };
    DFS(mark, grid, 1, 1);
    for (int i = 0 ; i<mark.size(); i++) {
        for (int j = 0; j < mark[i].size(); j++) {
            cout << mark[i][j] << " ";
        }
        cout << endl;
    }
    return 0;
}
1 1 1 0 0
1 1 0 0 0
0 0 0 0 0
0 0 0 0 0

2.3 BFS宽度搜索算法思路

在这里插入图片描述在这里插入图片描述

2.4 C++代码实现

在这里插入图片描述

class Solution {
public:
    void DFS(vector<vector<int>>& mark,vector<vector<char>>& grid,int x,int y){
        mark[x][y]=1;

        int dx[]={-1,1,0,0};
        int dy[]={0,0,-1,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_y<0||new_x>=mark.size()||new_y>=mark[new_x].size()){
                continue;
            }
            if(mark[new_x][new_y]==0&&grid[new_x][new_y]=='1'){
                DFS(mark,grid,new_x,new_y);
            }
        }
    }
    void BFS(vector<vector<int>>& mark, vector<vector<char>>& grid, int x, int y) {
        queue<pair<int, int>> Q;
        int dx[] = { -1,1,0,0 };
        int dy[] = { 0,0,-1,1 };

        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 new_x = x + dx[i];
                int new_y = y + dy[i];

                if (new_x < 0 || new_y < 0 || new_x >= mark.size() || new_y >= mark[new_x].size()) {
                    continue;
                }
                if (mark[new_x][new_y] == 0 && grid[new_x][new_y] == '1') {
                    mark[new_x][new_y] = 1;
                    Q.push(make_pair(new_x, new_y));
                }
            }
        }
    }
    int numIslands(vector<vector<char>>& grid) {
       int island=0;
       vector<vector<int>> mark;
       for(int i=0;i<grid.size();i++){
           mark.push_back(vector<int>());
           for(int j=0;j<grid[i].size();j++){
               mark[i].push_back(0);
           }
       } 

       for(int x=0;x<grid.size();x++){
           for(int y=0;y<grid[x].size();y++){
               if(mark[x][y]==0&&grid[x][y]=='1'){
                   DFS(mark,grid,x,y);//或者BFS(mark,grid,x,y);
                   island++;
               }
           }
       } 
       return island;

    }
};

3.单词接龙

3.1 题目描述

字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列:

序列中第一个单词是 beginWord 。
序列中最后一个单词是 endWord 。
每次转换只能改变一个字母。
转换过程中的中间单词必须是字典 wordList 中的单词。

给你两个单词 beginWord 和 endWord 和一个字典 wordList ,找到从 beginWord 到 endWord 的 最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0。

示例 1:

输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
输出:5
解释:一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", 返回它的长度 5。

示例 2:

输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log"]
输出:0
解释:endWord "cog" 不在字典中,所以无法进行转换。

3.2 算法思路

在这里插入图片描述
在这里插入图片描述

	bool connect(const string& word1,const string& word2){
        int cnt=0;
        for(int i=0;i<word1.length();i++){
            if(word1[i]!=word2[i]){
                cnt++;
            }
        }
        return cnt==1;
    }
    void construct_graph(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<strng>();
        }
        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]);
                }
            }
        }
    }

3.3 C++代码实现

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    bool connect(const string& word1,const string& word2){
        int cnt=0;
        for(int i=0;i<word1.length();i++){
            if(word1[i]!=word2[i]){
                cnt++;
            }
        }
        return cnt==1;
    }
    void construct_graph(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]);
                }
            }
        }
    }
    int BFS_graph(string& beginWord,string& endWord,map<string,vector<string>>& graph){
        queue<pair<string,int>> Q;
        set<string> visit;

        Q.push(make_pair(beginWord,1));
        visit.insert(beginWord);

        while(!Q.empty()){
            string node=Q.front().first;
            int step=Q.front().second;
            Q.pop();

            if(node==endWord){
                return step;
            }
            vector<string> neighbor=graph[node];
            for(int i=0;i<neighbor.size();i++){
                if(visit.find(neighbor[i])==visit.end()){
                    Q.push(make_pair(neighbor[i],step+1));
                    visit.insert(neighbor[i]);
                }
            }
        }
        return 0;
    }
    int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
        map<string,vector<string>> graph;
        construct_graph(beginWord,wordList,graph);
        int result=BFS_graph(beginWord,endWord,graph);
        return result;
    }
};

4.单词接龙 II

4.1 题目描述

按字典 wordList 完成从单词 beginWord 到单词 endWord 转化,一个表示此过程的 转换序列 是形式上像 beginWord -> s1 -> s2 -> … -> sk 这样的单词序列,并满足:

每对相邻的单词之间仅有单个字母不同。
转换过程中的每个单词 si(1 <= i <= k)必须是字典 wordList 中的单词。
注意,beginWord 不必是字典 wordList 中的单词。
sk == endWord

给你两个单词 beginWord 和 endWord ,以及一个字典 wordList 。请你找出并返回所有从 beginWord 到 endWord 的 最短转换序列 ,如果不存在这样的转换序列,返回一个空列表。每个序列都应该以单词列表 [beginWord, s1, s2, …, sk] 的形式返回。

示例 1:

输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
输出:[["hit","hot","dot","dog","cog"],["hit","hot","lot","log","cog"]]
解释:存在 2 种最短的转换序列:
"hit" -> "hot" -> "dot" -> "dog" -> "cog"
"hit" -> "hot" -> "lot" -> "log" -> "cog"

示例 2:

输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log"]
输出:[]
解释:endWord "cog" 不在字典 wordList 中,所以不存在符合要求的转换序列。

4.2 算法思路

在这里插入图片描述
在这里插入图片描述

5.火柴拼正方形

5.1 题目描述

还记得童话《卖火柴的小女孩》吗?现在,你知道小女孩有多少根火柴,请找出一种能使用所有火柴拼成一个正方形的方法。不能折断火柴,可以把火柴连接起来,并且每根火柴都要用到。

输入为小女孩拥有火柴的数目,每根火柴用其长度表示。输出即为是否能用所有的火柴拼成正方形。

示例 1:

输入: [1,1,2,2,2]
输出: true

解释: 能拼成一个边长为2的正方形,每边两根火柴。

示例 2:

输入: [3,3,3,3,4]
输出: false

解释: 不能用所有火柴拼成一个正方形。

5.2 算法思路

在这里插入图片描述

5.3 代码实现

class Solution {
public:
    bool makesquare(vector<int>& matchsticks) {
        if(matchsticks.size()<4){
            return false;
        }
        int sum=0;
        for(int i=0;i<matchsticks.size();i++){
            sum+=matchsticks[i];
        }
        if(sum%4){
            return false;
        }
        sort(matchsticks.rbegin(),matchsticks.rend());
        int bucket[4]={0};
        return generate(0,matchsticks,sum/4,bucket);
    }
private:
    bool generate(int i,vector<int>& matchsticks,int target,int bucket[]){
        if(i>=matchsticks.size()){
            return bucket[0]==target&&bucket[1]==target&&bucket[2]==target&&bucket[3]==target;
        }
        for(int j=0;j<4;j++){
            if(bucket[j]+matchsticks[i]>target){
                continue;
            }
            bucket[j]+=matchsticks[i];
            if(generate(i+1,matchsticks,target,bucket)){
                return true;
            }
            bucket[j]-=matchsticks[i];
        }
        return false;
    }
};

5.4 算法思路2

在这里插入图片描述

5.5 代码实现

class Solution {
public:
    bool makesquare(vector<int>& matchsticks){
        if(matchsticks.size()<4){
            return false;
        }
        int sum=0;
        for(int i=0;i<matchsticks.size();i++){
            sum+=matchsticks[i];
        }
        if(sum%4){
            return false;
        }
        int target=sum/4;
        vector<int> ok_subset;
        vector<int> ok_half;
        int all=1<<matchsticks.size();
        for(int i=0;i<all;i++){
            int sum=0;
            for(int j=0;j<matchsticks.size();j++){
                if(i&(1<<j)){
                    sum+=matchsticks[j];
                }
            }
            if(sum==target){
                ok_subset.push_back(i);
            }
        }

        for(int i=0;i<ok_subset.size();i++){
            for(int j=i+1;j<ok_subset.size();j++){
                if((ok_subset[i]&ok_subset[j])==0){
                    ok_half.push_back(ok_subset[i]|ok_subset[j]);
                }
            }
        }
        for(int i=0;i<ok_half.size();i++){
            for(int j=i+1;j<ok_half.size();j++){
                if((ok_half[i]&ok_half[j])==0){
                    return true;
                }
            }
        }
        return false;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值