一:单词搜索
题目:
给定一个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;
}
}
}
};