深度优先其实就是回溯算法,也就是暴力穷举,所以效率并不高。深度优先常常使用递归来进行编码,套路如下:做出选择;递归;撤销选择;只需要注意递归的退出点就可以了。
695. 岛屿的最大面积
class Solution {
public:
int maxAreaOfIsland(vector>& 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>& 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;
}
};
46. 全排列
class Solution {
public:
vector> permute(vector& nums) {
vector path;
vector> result;
dfs(nums,path,result);
return result;
}
void dfs(vector& nums, vector& path, vector>& 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> permuteUnique(vector& nums) {
vector path, index;
vector> 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& nums, vector& index, vector& path, vector>& result)
{
if (nums.size() == path.size())
{
result.emplace_back(path);
return;
}
for (int i=0;i
剑指 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> pathSum(TreeNode* root, int target) {
vector> r;
vector path;
backTrack(r,path,root,target);
return r;
}
void backTrack(vector>& r, vector& 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();
}
}
};
剑指 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 path_p = getPath(root, p);
vector 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 getPath(TreeNode* root, TreeNode* target) {
vector path;
dfs(root, target, path);
return path;
}
bool dfs(TreeNode* root, TreeNode* target, vector& 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;
}
};
剑指 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);
}
};
剑指 Offer 12. 矩阵中的路径
class Solution {
public:
bool exist(vector>& board, string word) {
bool find = false;
int row = board.size(), col = board[0].size();
vector> visited(row, vector(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>& board, const string& word, vector>& 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;
}
};
剑指 Offer 38. 字符串的排列
class Solution {
public:
//方法一
// vector rec;
// vector 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 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 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 permutation(string s) {
int n = s.size();
helper(s, 0, n-1);
return vector(rec.begin(), rec.end());
}
};
130. 被围绕的区域
class Solution {
public:
/* 方法一
先用 for 循环遍历棋盘的四边,用 DFS 算法把那些与边界相连的O换成一个特殊字符,比如#;
然后再遍历整个棋盘,把剩下的O换成X,把#恢复成O。这样就能完成题目的要求,时间复杂度 O(MN)。
*/
void solve(vector>& board) {
int n = board.size(), m = board[0].size();
vector> visited(n, vector(m,false));
for (int c=0;c>& board, vector>& visited, int r, int c)
{
if (r < 0 || r >= board.size() || c < 0 || c >= board[0].size())
return;
if (visited[r][c])
return;
visited[r][c] = true;
if (board[r][c] == 'O')
{
board[r][c] = '#';
dfs(board, visited, r-1, c);
dfs(board, visited, r+1, c);
dfs(board, visited, r, c-1);
dfs(board, visited, r, c+1);
}
visited[r][c] = false;
}
};
//方法二:使用UnionFind
class Solution {
public:
/* 方法一
先用 for 循环遍历棋盘的四边,用 DFS 算法把那些与边界相连的O换成一个特殊字符,比如#;
然后再遍历整个棋盘,把剩下的O换成X,把#恢复成O。这样就能完成题目的要求,时间复杂度 O(MN)。
*/
// void solve(vector>& board) {
// int n = board.size(), m = board[0].size();
// vector> visited(n, vector(m,false));
// for (int c=0;c>& board, vector>& visited, int r, int c)
// {
// if (r < 0 || r >= board.size() || c < 0 || c >= board[0].size())
// return;
// if (visited[r][c])
// return;
// visited[r][c] = true;
// if (board[r][c] == 'O')
// {
// board[r][c] = '#';
// dfs(board, visited, r-1, c);
// dfs(board, visited, r+1, c);
// dfs(board, visited, r, c-1);
// dfs(board, visited, r, c+1);
// }
// visited[r][c] = false;
// }
//方法二:使用UnionFind
class UF
{
public:
UF(int n)
{
count = n;
parent = new int[n];
size = new int[n];
for (int i = 0; i < n; i++)
{
parent[i] = i;
size[i] = 1;
}
}
~UF()
{
delete[] parent;
delete[] size;
}
void Union(int p, int q)
{
int rootP = Find(p);
int rootQ = Find(q);
if (rootP == rootQ)
return;
// 小树接到大树下面,较平衡
if (size[rootP] > size[rootQ])
{
parent[rootQ] = rootP;
size[rootP] += size[rootQ];
}
else
{
parent[rootP] = rootQ;
size[rootQ] += size[rootP];
}
count--;
}
bool Connected(int p, int q)
{
int rootP = Find(p);
int rootQ = Find(q);
return rootP == rootQ;
}
int Find(int x)
{
while (parent[x] != x)
{
// 进行路径压缩
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
private:
// 连通分量个数
int count;
// 存储一棵树
int* parent;
// 记录树的“重量”
int* size;
};
void solve(vector>& board) {
int m = board.size(), n = board[0].size();
// 给 dummy 留一个额外位置
UF uf(m * n + 1);
int dummy = m * n;
// 将首列和末列的 O 与 dummy 连通
for (int i = 0; i < m; i++)
{
if (board[i][0] == 'O')
uf.Union(i * n, dummy);
if (board[i][n - 1] == 'O')
uf.Union(i * n + n - 1, dummy);
}
// 将首行和末行的 O 与 dummy 连通
for (int j = 0; j < n; j++)
{
if (board[0][j] == 'O')
uf.Union(j, dummy);
if (board[m - 1][j] == 'O')
uf.Union(n * (m - 1) + j, dummy);
}
// 方向数组 d 是上下左右搜索的常用手法
int d[4][2] = {{1,0}, {0,1}, {0,-1}, {-1,0}};
for (int i = 1; i < m - 1; ++i)
{
for (int j = 1; j < n - 1; ++j)
{
if (board[i][j] == 'O')
{
// 将此 O 与上下左右的 O 连通
for (int k = 0; k < 4; ++k)
{
int x = i + d[k][0];
int y = j + d[k][1];
if (board[x][y] == 'O')
uf.Union(x * n + y, i * n + j);
}
}
}
}
// 所有不和 dummy 连通的 O,都要被替换
for (int i = 1; i < m - 1; ++i)
for (int j = 1; j < n - 1; ++j)
if (!uf.Connected(dummy, i * n + j))
board[i][j] = 'X';
}
};
797. 所有可能的路径
剑指 Offer II 110. 所有路径
class Solution {
public:
vector> allPathsSourceTarget(vector>& graph) {
vector path;
vector> res;
dfs(graph, 0, path, res);
return res;
}
void dfs(vector>& graph, int index, vector& path, vector>& res)
{
path.push_back(index);
if (index == graph.size()-1)
{
res.emplace_back(path);
path.pop_back();
return;
}
for (int i : graph[index])
dfs(graph, i, path, res);
path.pop_back();
}
};
814. 二叉树剪枝
剑指 Offer II 047. 二叉树剪枝
/**
* 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:
TreeNode* pruneTree(TreeNode* root) {
if (!root)
{
return root;
}
if (root->val == 0)
{
root->left = pruneTree(root->left);
root->right = pruneTree(root->right);
if (!root->left && !root->right)
{
return NULL;
}
else
{
return root;
}
}
else
{
root->left = pruneTree(root->left);
root->right = pruneTree(root->right);
return root;
}
}
};
399. 除法求值
剑指 Offer II 111. 计算除法
class Solution {
public:
vector calcEquation(vector>& equations, vector& values, vector>& queries) {
vector r;
//转换成图: 一维是起始索引,二维是pair{终止节点,权重}
unordered_map> graph;
buildGraph(equations, values, graph);
for (auto& v : queries)
{
string first = v[0], second = v[1];
if (graph.count(first))
{
if (graph[first].count(second))
{
r.push_back(graph[first][second]);
}
else
{
if (first == second)
{
r.push_back(1.0);
}
else
{
double res = -1.0;
unordered_map visited;
visited[first] = true;
for (auto& item : graph[first])
{
res = dfs(graph[first][item.first], item.first, second, graph, visited);
if (-1.0 != res)
{
break;
}
}
visited[first] = false;
r.push_back(res);
if (-1.0 != res)
{
graph[first].insert({second, res});
graph[second].insert({first, 1.0 / res});
}
}
}
}
else
{
r.push_back(-1.0);
}
}
return r;
}
void buildGraph(vector>& equations, vector& values, unordered_map>& graph)
{
int n = equations.size();
for (int i=0;i>& graph, unordered_map& visited)
{
double res = -1.0;
do
{
if (visited[first])
break;
if (!graph.count(first) || !graph.count(second))
break;
if (first.compare(second) == 0)
{
res = 1.0;
break;
}
else
{
if (graph[first].count(second))
{
res = base * graph[first][second];
}
else
{
visited[first] = true;
for (auto& item : graph[first])
{
res = dfs(graph[first][item.first], item.first, second, graph, visited);
if (-1.0 != res)
{
res *= base;
break;
}
}
visited[first] = false;
}
}
}while(0);
return res;
}
};
129. 求根节点到叶节点数字之和
剑指 Offer II 049. 从根节点到叶节点的路径数字之和
/**
* 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:
int sumNumbers(TreeNode* root) {
vector v;
dfs(0, root, v);
return accumulate(v.begin(), v.end(), 0);
}
void dfs(int base, TreeNode* cur, vector& v)
{
if (!cur)
{
v.push_back(base);
}
if (!cur->left && !cur->right)
{
v.push_back(base*10 + cur->val);
}
else
{
if (cur->left)
{
dfs(base*10 + cur->val, cur->left, v);
}
if (cur->right)
{
dfs(base*10 + cur->val, cur->right, v);
}
}
}
};
剑指 Offer II 050. 向下的路径节点之和
437. 路径总和 III
/**
* 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:
int pathSum(TreeNode* root, int targetSum) {
if (!root)
return 0;
return dfs(root, targetSum) + pathSum(root->left, targetSum) + pathSum(root->right, targetSum);
}
int dfs(TreeNode* root, int targetSum)
{
if (!root)
return 0;
if (targetSum == root->val)
{
return 1 + dfs(root->left, targetSum - root->val) + dfs(root->right, targetSum - root->val);
}
return dfs(root->left, targetSum - root->val) + dfs(root->right, targetSum - root->val);
}
};
2.14
2.15
2.16