算法4-----综合训练(4)

一:单词搜索

题目:

给定一个m*n的二位字符网格和一个字符串单词。如果单词存在于网格中,返回true,不然,返回false。

注意:单词必须按照字母顺序,通过相邻的单元格内的字母构成,同一个单元格内的字母不可以被重复使用。

方法:

1:画出决策树

2:算法原理

dfs函数的设计:

dfs(board,i,j,s,pos)

(board表示题给的网格,i,j表示当前的位置,s表示要查找的单词,pos表示当前查找到的位置)

细节部分:

为了避免查找当同一位置的字母,有两种方法可以解决:

(1)创建一个与网格同等大小的数组,标记每个位置是否已被使用

bool check[][];

(2)将已经用过的位置里的字母进行篡改(该种方法只适用于原数组可以被修改的情况)

特殊方法:

利用向量的方式,定义上下左右四个位置

首先,设立两个数组:int dx[4] = {0,0,1,-1};int dy[4] = {-1,1,0,0}

将这当前位置的坐标分别加上这两个数组进行的遍历,就可以轻松得到当前位置上下左右四个位置的坐标

class Solution {
    bool check[7][7];//判断是否已被使用
    int m,n;
    
public:
    bool exist(vector<vector<char>>& board, string word) {
    m = board.size(),n = board[0].size();
    for(int i = 0;i<m;i++)
    {
        for(int j = 0;j<n;j++)
        {
            if(board[i][j] == word[0])
            {
                check[i][j] = true;
                if(dfs(board,i,j,word,1))  return true;
                check[i][j] = false;
            }
        }
    }
    return false;
    }
    int dx[4] = {0,0,-1,1};
    int dy[4] = {1,-1,0,0};
    bool dfs(vector<vector<char>>& board,int i,int j,string& word,int pos)
    {
        if(pos == word.size())
        return true;

        //1
        //向量的方式,定义上下左右四个位置
        for(int k = 0;k<4;k++)
        {
            int x = i+dx[k],y = j+dy[k];
            //是否越界并且未被使用
            if(x>=0&&x<m&&y>=0&&y<n&&!check[x][y]&&board[x][y]==word[pos])
            {
                check[x][y] = true;
                if(dfs(board,x,y,word,pos+1))  return true;
                check[x][y] = false;
            }
        }
        return false;
    }
};

二:黄金矿工(与单词搜索思路基本一致)

题目:

你要开发一座金矿,地质勘测学家已经探明了这座金矿中的资源分布,并用大小为 m * n 的网格 grid 进行了标注。每个单元格中的整数就表示这一单元格中的黄金数量;如果该单元格是空的,那么就是 0

为了使收益最大化,矿工需要按以下规则来开采黄金:

(1)每当矿工进入一个单元,就会收集该单元格中的所有黄金。

(2)矿工每次可以从当前位置向上下左右四个方向走。

(3)每个单元格只能被开采(进入)一次。

(4)不得开采(进入)黄金数目为 0 的单元格。

(5)矿工可以从网格中 任意一个 有黄金的单元格出发或者是停止。

方法:

1:画出决策树(与上一题基本一致,为避免重复,在此省略)

2:算法原理

与上一题的单词搜索思路基本一致,防止重复的方法变为了要将原先的单元格进行改变

dfs函数的设计:

void dfs(grid,i,j,path)((i,j)为当时位置的坐标,path记录每一步走到的值并把它加起来)

PS:不需要递归出口,用一个函数将ret与path进行比较得到最大的那个即可

class Solution {
    bool vis[16][16];
    int ret;//记录最后采集到的矿石
    int dx[4] = {0,0,1,-1};
    int dy[4] = {1,-1,0,0};
    int m,n;
public:
    int getMaximumGold(vector<vector<int>>& grid) {
        m = grid.size(),n = grid[0].size();
        for(int i = 0;i<m;i++)
        {
            for(int j = 0;j<n;j++)
            {
                if(grid[i][j]!=0)
                {
                   vis[i][j] = true;
                    dfs(grid,i,j,grid[i][j]);
                    vis[i][j] = false;
                }
            }
        }
    return ret;
    }
    void dfs(vector<vector<int>>& grid,int i,int j,int path)
    {
        //不需要递归出口
        ret = max(ret,path);
        for(int k = 0;k<4;k++)
        {
            int x = i+dx[k],y = j+dy[k];
            if(x>=0&&x<m&&y>=0&&y<n&&!vis[x][y]&&grid[x][y])
            {
                vis[x][y] = true;
                dfs(grid,x,y,path+grid[x][y]);
                vis[x][y] = false;
            }
        }
    }
};

三:不同路径3

题目:

在二维网格 grid 上,有 4 种类型的方格:

(1)1 表示起始方格。且只有一个起始方格。

(2)2 表示结束方格,且只有一个结束方格。

(3)0 表示我们可以走过的空方格。

(4)-1 表示我们无法跨越的障碍。

返回在四个方向(上、下、左、右)上行走时,从起始方格到结束方格的不同路径的数目。

每一个无障碍方格都要通过一次,但是一条路径中不能重复通过同一个方格。

方法:

1:画出决策树(与前面的思路基本一致)

2:算法原理

直接进行暴力搜索,计数到2的步数,与原本网格中0的个数进行比较,合法就直接算作一条有效路径,不合法直接返回即可

class Solution {
    bool vis[21][21];
    int dx[4] = {1,-1,0,0};
    int dy[4] = {0,0,1,-1};
    int ret;
    int m,n,step;
public:
    int uniquePathsIII(vector<vector<int>>& grid) {
    m = grid.size(),n = grid[0].size();
    int bx = 0,by = 0;
    for(int i = 0;i<m;i++)
    {
        for(int j = 0;j<n;j++)
        {
            if(grid[i][j]==0)  step++;
            else if(grid[i][j]==1)
            {
                bx = i;
                by = j;
            }
        }
    }
    step+=2;
    vis[bx][by] = true;
    dfs(grid,bx,by,1);
    return ret;
    }

    void dfs(vector<vector<int>>& grid,int i,int j,int count)
    {
        if(grid[i][j]==2)
        {
            if(count==step)
            ret++;
            return;
        }
        for(int k = 0;k<4;k++)
        {
            int x = i+dx[k],y = j+dy[k];
            if(x>=0&&x<m&&y>=0&&y<n&&!vis[x][y]&&grid[x][y]!=-1)
            {
                vis[x][y] = true;
                dfs(grid,x,y,count+1);
                vis[x][y] = false;
            }
        }
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值