DFS试题集合

你有一个用于表示一片土地的整数矩阵land,该矩阵中每个点的值代表对应地点的海拔高度。若值为0则表示水域。由垂直、水平或对角连接的水域为池塘。池塘的大小是指相连接的水域的个数。编写一个方法来计算矩阵中所有池塘的大小,返回值需要从小到大排序。

示例:

输入:
[
[0,2,1,0],
[0,1,0,1],
[1,1,0,1],
[0,1,0,1]
]
输出: [1,2,4]

int cnt=0;
    vector<int> pondSizes(vector<vector<int>>& land) {
         int row=land[0].size();
         int width=land.size();
         vector<int>ans;
         for(int i=0;i<width;i++)
          for(int j=0;j<row;j++)
          {
             if(land[i][j]!=0) continue;
            else 
            {
               dfs(i,j,land);
               if(cnt!=0)
               {
                ans.push_back(cnt);
                cnt=0;}
            }
          }
          sort(ans.begin(),ans.end());
          return ans;
    }
    void dfs(int i,int j,vector<vector<int>>& land)
    {
        int r=land[0].size();
        int w=land.size();
        if(i>=0&&j>=0&&i<w&&j<r)
           {
               if(land[i][j]==0)
               {
                   land[i][j]=-1;
                   cnt++;
               }
               else
                return;
           }
           else 
           return;
        dfs(i+1,j,land);
        dfs(i-1,j,land);
        dfs(i+1,j-1,land);
        dfs(i+1,j+1,land);
        dfs(i-1,j-1,land);
        dfs(i-1,j+1,land);
        dfs(i,j-1,land);
        dfs(i,j+1,land);
    }

回溯+深度搜索
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如 [abcesfcsadee]\begin{bmatrix} a & b & c &e \ s & f & c & s \ a & d & e& e\ \end{bmatrix}\quad⎣⎡​asa​bfd​cce​ese​⎦⎤​ 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

bool hasPath(char*matrix, int rows, int cols, char*str)
    {
         //bool visited1[cols*rows];
         vector<bool> visited(rows*cols,false);
         bool condition=false;
        for(int i=0;i<rows;i++)
            for(int j=0;j<cols;j++)
            {
               condition= (condition || dfs(matrix,i,j,rows,cols,str,visited));
            }
        return condition;    
    }
    bool dfs(char *m,int x,int y,int rows,int cols,char*c,vector<bool> visited)
    {
        if(x>=rows||y>=cols||x<0||y<0)//越界点
            return false;
        
        if(*c==m[x*cols+y]&&!visited[x*cols+y])
        {
            if(*(c+1)==0)//停止搜索的条件
                return true;
            visited[x*cols+y]=true;
            bool f=dfs(m,x+1,y,rows,cols,(c+1),visited)||dfs(m,x,y+1,rows,cols,(c+1),visited)||dfs(m,x,y-1,rows,cols,(c+1),visited)||dfs(m,x-1,y,rows,cols,(c+1),visited);
            //向四个方向出发
            if(!f)
              visited[x*cols+y]=false;//回溯@[TOC]@[TOC]((这里写自定义目录标题))
            return f;
               
        }
        else 
        {
            return false;
        }
        
    }
   

有一个二维矩阵 grid ,每个位置要么是陆地(记号为 0 )要么是水域(记号为 1 )。

我们从一块陆地出发,每次可以往上下左右 4 个方向相邻区域走,能走到的所有陆地区域,我们将其称为一座「岛屿」。

如果一座岛屿 完全 由水域包围,即陆地边缘上下左右所有相邻区域都是水域,那么我们将其称为 「封闭岛屿」。

请返回封闭岛屿的数目。

示例 1:在这里插入图片描述

输入:grid = [[1,1,1,1,1,1,1,0],[1,0,0,0,0,1,1,0],[1,0,1,0,1,1,1,0],[1,0,0,0,0,1,0,1],[1,1,1,1,1,1,1,0]]
输出:2
解释:
灰色区域的岛屿是封闭岛屿,因为这座岛屿完全被水域包围(即被 1 区域包围)。

class Solution {
public:
    //返回岛屿是否到达边界
    bool dfs(vector<vector<int>>& grid, int r, int c){
        if(r<0 || r>=grid.size() || c<0 || c>=grid[0].size()){
            return true; //是否到达边界,一次dfs搜索中只要有一个地方最终走到这儿就不是封闭岛屿了
        }

        if(grid[r][c]!=0){ //如果是海洋或是已经访问过的陆地则返回false,因为这两种情况不需要继续遍历,且也没找到边界
            return false;
        }

        //当前是陆地则继续
        grid[r][c] = 2; //标记为2表示已经访问过,也有人标记为海洋,但我觉得用一个独立的值更清晰些

        //四方向都要遍历到,不能因为某个方向找到边界就直接退出,因为这样找到的岛屿不完整,结果就错了
        bool res1 = dfs(grid, r-1, c);
        bool res2 = dfs(grid, r+1, c);
        bool res3 = dfs(grid, r, c-1);
        bool res4 = dfs(grid, r, c+1);
        return res1 || res2 || res3 || res4; //四方向遍历下去的结果,有任意一个方向接触边界就行
    }

    int closedIsland(vector<vector<int>>& grid) {
        int nr = grid.size();
        if(nr==0){
            return 0;
        }
        int nc = grid[0].size();
        int num = 0;

        for(int i=0; i<nr; ++i){
            for(int j=0; j<nc; ++j){
                if(grid[i][j]==0){  //岛屿题常规套路,找到一个陆地开始遍历
                    if(!dfs(grid,i,j)){ //如果dfs搜索完了发现这个岛不是接触边界,则封闭岛屿数增加
                        num++;
                    }
                }
            }
        }
        return num;
    }
};

在这里插入图片描述

int networkDelayTime(vector<vector<int>>& times, int N, int K) {
        const int INF = 0x3f3f3f3f;
        vector<vector<int>>graph(N+1, vector<int>(N+1, INF));//相当于N个节点,每个节点有N个输出节点(分别表示i到j的                                                  //长度),第一个维度存放INF,下边有用;         
        for (vector<int> each : times) { 
            graph[each[0]][each[1]] = each[2]; //将times中的路径关系初始化到graph;
        }
        vector<int>dist(graph[K]); //将graph第K+1个元素作为dist,因为第一个用作默认值;
        vector<bool>st(N+1,false);//表示是否遍历过,记得赋初值
        st[K] = true;
        dist[K] = 0; //初始化->自己到自己的距离为0,且这个节点已经激活;
        for (int i = 0; i < N ; i++) {//这里是n-1,因为有N-1个节点没有激活;
            //找最短
            int t = 0;
            for (int i = 1; i <= N; i++) {//从1开始,到N,第0个就是为了放刚开始的t的;
                if (st[i] == false && (t ==0 || dist[i] < dist[t])) {
                    t = i;//更新最短路径
                }
            }
            st[t] = true; //将最小距离的索引处st设为true;
            for (int i = 1; i <= N; i++) {
                if (st[i] == false) { //遍历所有未激活的节点;
                    dist[i] = min(dist[i], dist[t] + graph[t][i]);
                }
            }
        }
        int ans = *max_element(dist.begin()+1, dist.end());//返回最大值
        return  ans == INF ? -1 : ans;

    }

在这里插入图片描述

void dfs(vector<int>& coins,int amount,int index,int count,int &ans)
    {
        if(amount==0)
          {
           ans=min(ans,count);
           return ;
          }
        if(coins.size()==index)
          return;
        for(int i=amount/coins[index];i>=0&&i+count<ans;i--)
        {
            dfs(coins,amount-i * coins[index],index+1,count+i,ans);
        }
    }
    int coinChange(vector<int>& coins, int amount) {
      sort(coins.rbegin(),coins.rend());
      int ans=INT_MAX;
      dfs(coins,amount,0,0,ans);
      //if(amount!=0)
        //return -1;
      //return ans;
      return ans == INT_MAX ? -1 : ans;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值