文章目录
DFS
题目1 : 单词搜索
给定一个二维网格和一个单词,找出该单词是否存在于网格中。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例:
board =
[
[‘A’,‘B’,‘C’,‘E’],
[‘S’,‘F’,‘C’,‘S’],
[‘A’,‘D’,‘E’,‘E’]
]
给定 word = “ABCCED”, 返回 true.
给定 word = “SEE”, 返回 true.
给定 word = “ABCB”, 返回 false.
解题思路:简单DFS,注意边界条件的判断和点的回溯(index和visted)
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Solution
{
public:
string str;
vector<vector<char>> map;
vector<vector<bool>> visted;
int index = 1;
int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
bool DFS(int x, int y, int deep)
{
auto row = map.size();
auto col = map[0].size();
auto len = str.size();
if (deep == len && map[x][y] == str[len - 1])//这里是两个条件
{
return true;
}
for (int i = 0; i < 4; i++)
{
auto xx = x + dir[i][0];
auto yy = y + dir[i][1];
if (xx < 0 || xx >= row || yy < 0 || yy >= col || visted[xx][yy] || map[xx][yy] != str[index])
continue;
else
{
index++;
visted[xx][yy] = true;
if (DFS(xx, yy, deep + 1))
return true;
visted[xx][yy] = false ;
index--;
}
}
return false;
}
bool exist(vector<vector<char>> &board, string word)
{
auto row = board.size();
auto col = board[0].size();
vector<bool> temp(col, false);
vector<vector<bool>> temp_visted(row, temp);
str = word;
map = board;
visted = temp_visted;
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (visted[i][j] == false && board[i][j] == word[0])
{
visted[i][j] = true;
if (DFS(i, j, 1))
return true;
visted[i][j] = false;
}
}
}
return false;
}
};
题目2: 78. 子集
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
DFS
class Solution
{
public:
vector<vector<int>> subsets(vector<int> &nums)
{
result.push_back(path);
dfs(0, nums);
return result;
}
private:
vector<vector<int>> result;
vector<int> path;
void dfs(int index, const vector<int> &nums)
{
for (int i = index; i < nums.size(); i++)
{
path.push_back(nums[i]);
result.push_back(path);
dfs(i + 1, nums);
path.pop_back();
}
}
};
还有另外两种思路:
- 可以直接从后遍历,遇到一个数就把所有子集加上该数组成新的子集,遍历完毕即是所有子集
- 位运算
200. 岛屿的个数
给定一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。
示例 1:
输入:
11110
11010
11000
00000
输出: 1
示例 2:
输入:
11000
11000
00100
00011
输出: 3
思路1:与找油田的题目类似,我主要坑在了grid 是char类型的上面.就是找到一块一块的地区就行,最直观的就是dfs,参考代码如下(为了普遍性,我没有将visted这个数组去掉以进行优化)
class Solution
{
public:
int numIslands(vector<vector<char>> &grid)
{
auto row = grid.size();
if (row <= 0)
return 0;
auto col = grid[0].size();
vector<vector<bool>> temp_visted(row, vector<bool>(col, false));
visted = temp_visted;
int result = 0;
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (visted[i][j] == false && grid[i][j] == '1')
{
visted[i][j] = true;
dfs(grid, i, j);
result++;
}
}
}
return result;
}
private:
int dir[4][2] = {
{1, 0},
{0, 1},
{-1, 0},
{0, -1}};
vector<vector<bool>> visted;
bool check(vector<vector<char>> &grid, int i, int j)
{
//i 行 j 列
if (i < 0 || i >= grid.size() || j < 0 || j >= grid[0].size())
return false;
if (visted[i][j] == true)
return false;
if (grid[i][j] == '0') //注意是字符,我就坑在了这里
return false;
return true;
}
void dfs(vector<vector<char>> &grid, int x, int y)
{
for (int i = 0; i < 4; i++)
{
int xx = x + dir[i][0];
int yy = y + dir[i][1];
if (check(grid, xx, yy))
{
visted[xx][yy] = true;
dfs(grid, xx, yy);
}
}
}
};
思路2:bfs
思路3:dfs+bfs
public class Solution {
public int numIslands(char[][] grid) {
int num = 0;
for(int i = 0; i < grid.length; i++) {
for(int j = 0; j < grid[0].length; j++) {
if(grid[i][j] != '1') continue;
dfs(grid, i, j); //dfs 和 bfs 结合,将 (i,j)及附近能联通的所有值为1的点值置为1
num++;
}
}
return num;
}
private void dfs(char[][] grid, int i, int j) { //dfs深度遍历
if(i >= grid.length || i < 0 || j < 0 ||
j >= grid[0].length || grid[i][j] != '1') return;
grid[i][j] = '2';
dfs(grid, i+1, j); //这四个 dfs 整体看来是 bfs
dfs(grid, i, j+1);
dfs(grid, i-1, j);
dfs(grid, i, j-1);
}
}