1 dfs简介
深度优先其实就是回溯算法,也就是暴力穷举,所以效率并不高。深度优先尝尝使用递归来进行编码,套路如下:做出选择;递归;撤销选择;并且需要注意递归的退出点就可以了。
2 力扣题目
2.1 岛屿的最大面积
695. 岛屿的最大面积
class Solution {
public:
int maxAreaOfIsland(vector<vector<int>>& grid) {
int maxArea = 0;
for (int i = 0; i < grid.size(); ++i)
{
for (int j = 0; j < grid[0].size(); ++j)
{
if (grid[i][j])
{
maxArea = std::max(maxArea, helper(grid, i, j));
}
}
}
return maxArea;
}
int helper(vector<vector<int>>& grid, int r, int c)
{
int area = 0;
if (r >=0 && r < grid.size() && c >=0 && c < grid[0].size() && grid[r][c])
{
area += 1;
grid[r][c] = 0;
if ((c-1) >=0 && grid[r][c-1])
{
area += helper(grid, r, c-1);
}
if ((c+1) < grid[0].size() && grid[r][c+1])
{
area += helper(grid, r, c+1);
}
if ((r-1) >=0 && grid[r-1][c])
{
area += helper(grid, r-1, c);
}
if ((r+1) < grid.size() && grid[r+1][c])
{
area += helper(grid, r+1, c);
}
}
return area;
}
};
2.2 不含重复数字的全排列
46. 全排列
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<int> path;
vector<vector<int>> result;
dfs(nums,path,result);
return result;
}
void dfs(vector<int>& nums, vector<int>& path, vector<vector<int>>& result)
{
if (nums.size() == path.size())
{
result.emplace_back(path);
return;
}
for (int n : nums)
{
if (std::find(path.begin(), path.end(), n) != path.end())
{
continue;
}
path.push_back(n);
dfs(nums,path,result);
path.pop_back();
}
}
};
47. 全排列 II
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
vector<int> path, index;
vector<vector<int>> result;
dfs(nums,index,path,result);
std::sort(result.begin(),result.end());
result.resize(std::distance(result.begin(),std::unique(result.begin(),result.end())));
return result;
}
void dfs(vector<int>& nums, vector<int>& index, vector<int>& path, vector<vector<int>>& result)
{
if (nums.size() == path.size())
{
result.emplace_back(path);
return;
}
for (int i=0;i<nums.size();++i)
{
if (std::find(index.begin(), index.end(), i) != index.end())
{
continue;
}
index.push_back(i);
path.push_back(nums[i]);
dfs(nums,index,path,result);
index.pop_back();
path.pop_back();
}
}
};
2.3 二叉树中和为某一值的路径
剑指 Offer 34. 二叉树中和为某一值的路径
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> pathSum(TreeNode* root, int target) {
vector<vector<int>> r;
vector<int> path;
backTrack(r,path,root,target);
return r;
}
void backTrack(vector<vector<int>>& r, vector<int>& path, TreeNode* root, int target)
{
if (root)
{
path.push_back(root->val);
if (root->val == target && !root->left && !root->right)
{
r.push_back(path);
}
backTrack(r,path,root->left,target-root->val);
backTrack(r,path,root->right,target-root->val);
path.pop_back();
}
}
};
2.4 二叉树的最近公共祖先
剑指 Offer 68 - II. 二叉树的最近公共祖先
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
vector<TreeNode*> path_p = getPath(root, p);
vector<TreeNode*> path_q = getPath(root, q);
TreeNode* ancestor;
for (int i = 0; i < path_p.size() && i < path_q.size(); ++i)
{
if (path_p[i] == path_q[i])
{
ancestor = path_p[i];
}
else
{
break;
}
}
return ancestor;
}
vector<TreeNode*> getPath(TreeNode* root, TreeNode* target) {
vector<TreeNode*> path;
dfs(root, target, path);
return path;
}
bool dfs(TreeNode* root, TreeNode* target, vector<TreeNode*>& path)
{
bool find = false;
do
{
if (root)
{
path.push_back(root);
if (root == target)
{
find = true;
break;
}
if (dfs(root->left, target, path) || dfs(root->right, target, path))
{
find = true;
break;
}
path.pop_back();
}
} while(0);
return find;
}
};
2.5 二叉搜索树转换成双向链表
剑指 Offer 36. 二叉搜索树与双向链表
/*
// Definition for a Node.
class Node {
public:
int val;
Node* left;
Node* right;
Node() {}
Node(int _val) {
val = _val;
left = NULL;
right = NULL;
}
Node(int _val, Node* _left, Node* _right) {
val = _val;
left = _left;
right = _right;
}
};
*/
class Solution {
public:
Node* treeToDoublyList(Node* root) {
if (!root)
{
return root;
}
Node *pre = NULL, *head = NULL;
backTrack(root, pre, head);
head->left = pre;
pre->right = head;
return head;
}
void backTrack(Node* cur, Node*& pre, Node*& head)
{
if (!cur)
{
return;
}
backTrack(cur->left, pre, head);
if (!pre)
{
head = cur;
}
else
{
pre->right = cur;
cur->left = pre;
}
pre = cur;
backTrack(cur->right, pre, head);
}
};
2.6 矩阵中的路径
剑指 Offer 12. 矩阵中的路径
class Solution {
public:
bool exist(vector<vector<char>>& board, string word) {
bool find = false;
int row = board.size(), col = board[0].size();
vector<vector<bool>> visited(row, vector<bool>(col, false));
do
{
if (board.empty())
{
if (word.empty())
{
find = true;
}
break;
}
for (int r = 0; r < row; ++r)
{
for (int c = 0; c < col; ++c)
{
if (backTrack(board, word, visited, 0, r, c))
{
find = true;
return find;
}
}
}
} while (0);
return find;
}
bool backTrack(vector<vector<char>>& board, const string& word, vector<vector<bool>>& visited, int pos, int r, int c)
{
bool find = false;
do
{
if (pos == word.size())
{
find = true;
break;
}
if (word.empty())
{
break;
}
int row = board.size(), col = board[0].size();
char ch = word[pos];
if (r >= 0 && r < row && c >= 0 && c < col)
{
if (visited[r][c])
{
break;
}
if (ch != board[r][c])
{
break;
}
visited[r][c] = true;
if (backTrack(board, word, visited, pos+1, r-1, c)
|| backTrack(board, word, visited, pos+1, r+1, c)
|| backTrack(board, word, visited, pos+1, r, c-1)
|| backTrack(board, word, visited, pos+1, r, c+1))
{
find = true;
break;
}
visited[r][c] = false;
}
} while (0);
return find;
}
};
2.7 字符串的排列
剑指 Offer 38. 字符串的排列
class Solution {
public:
//方法一
// vector<string> rec;
// vector<int> vis;
// void backtrack(const string& s, int i, int n, string& perm) {
// if (i == n) {
// rec.push_back(perm);
// return;
// }
// for (int j = 0; j < n; j++) {
// if (vis[j] || (j > 0 && !vis[j - 1] && s[j - 1] == s[j])) {
// continue;
// }
// vis[j] = true;
// perm.push_back(s[j]);
// backtrack(s, i + 1, n, perm);
// perm.pop_back();
// vis[j] = false;
// }
// }
// vector<string> permutation(string s) {
// int n = s.size();
// vis.resize(n);
// sort(s.begin(), s.end());
// string perm;
// backtrack(s, 0, n, perm);
// return rec;
// }
//方法二
unordered_set<string> rec;
void helper(string& s, int beginIndex, int endIndex)
{
if (beginIndex == endIndex)
{
rec.insert(s);
return;
}
for (int i=beginIndex;i<=endIndex;++i)
{
char c = s[i];
s[i] = s[beginIndex];
s[beginIndex] = c;
helper(s, beginIndex+1, endIndex);
c = s[i];
s[i] = s[beginIndex];
s[beginIndex] = c;
}
}
vector<string> permutation(string s) {
int n = s.size();
helper(s, 0, n-1);
return vector<string>(rec.begin(), rec.end());
}
};
2.8
2.9
2.10