本文内容是基于小象学院——林沐 《面试算法 LeetCode 刷题班》,后期仍将对相关内容进行不定期更新!
这里题目已经事先定义了一个,树节点的类型结构:
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
代码:
class Solution {
public:
vector> pathSum(TreeNode* root, int sum) {
vector> result;
vector path;
int path_value = 0;
preorder(root, path_value, sum, path, result);
return result;
}
void preorder(TreeNode *node, int & path_value, int sum, vector& path, vector>&result) {
if (!node)
{
return;
}
path_value += node->val;
path.push_back(node->val);
if (path_value == sum && !node->left && !node->right) // 除了值相等,还要保证当前的点是叶节点
{
result.push_back(path);
}
preorder(node->left, path_value, sum, path, result); //依次遍历左分支
preorder(node->right, path_value, sum, path, result); // 依次遍历右分支
// 开始运行下面的程序说明已经遍历到了叶节点,或者一个节点的左右节点均已经遍历完
path_value -= node->val; //返回之前的状态
path.pop_back();
}
};
思路:两个路径对应的路径,同时出现最后一个相同的节点。
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
vector path; // 声明遍历用的临时栈
vector node_p_path; // 存储p节点路径
vector node_q_path; // 存储q节点路径
int finish = 0; //记录是否搜索的变量finish
preorder(root, p, path, node_p_path, finish); // 计算节点p路径
path.clear();
finish = 0; // 清空状态,计算节点q路径
preorder(root, q, path, node_q_path, finish);
int path_len = 0; // 比较段路径长度
if (node_p_path.size() < node_q_path.size())
{
path_len = node_p_path.size();
}
else {
path_len = node_q_path.size();
}
TreeNode* result = NULL;
for (int i = 0; i < path_len; i++) {
if (node_p_path[i] == node_q_path[i])
{
result = node_p_path[i];
}
}
return result;
}
void preorder(TreeNode* node, TreeNode* search, vector &path, vector &result, int & finish) { // 注意输入都是引用
if (!node || finish ) // 当node为空或已找到search节点直接返回,结束搜索
{
return;
}
path.push_back(node); //先序遍历,将节点压入path 栈
if (node == search)
{
finish = 1; // 当找到 search 节点后,标记finish变量
result = path; // 将当前的path存储到result中
}
preorder(node->left, search, path, result, finish); // 深度遍历 node 左孩子
preorder(node->right, search, path, result, finish); // 深度遍历 node 右孩子
path.pop_back(); // 结束遍历node时,将node 节点弹出 path 栈
}
};
难点是需要将二叉树就地(in-place)转换为单链表。单链表中间节点顺序为二叉树前序遍历顺序。 方法一:
class Solution {
public:
void flatten(TreeNode* root) {
vector node_vec;
preorder(root,node_vec);
for (int i = 1; i < node_vec.size(); i++) {
node_vec[i-1]->left = NULL;
node_vec[i - 1]->right = node_vec[i];
}
}
void preorder(TreeNode*node, vector &node_vec) {
if (!node)
{
return;
}
node_vec.push_back(node);
preorder(node->left, node_vec);
preorder(node->right, node_vec);
}
};
方法二: (就地法)
分别将二叉树根节点的左子树和右子树分别转成链表,然后将链表进行拼接。
class Solution {
public:
void flatten(TreeNode* root) {
TreeNode* last = NULL;
preorder(root,last);
}
void preorder(TreeNode*node, TreeNode* &last) {
if (!node)
{
return;
}
if (!node->left && !node->right)
{
last = node;
return;
}
TreeNode *left = node->left;
TreeNode *right = node->right;
TreeNode *left_last = NULL;
TreeNode *right_last = NULL;
if (left) {
preorder(left, left_last);
node->left = NULL;
node->right = left;
last = left_last;
}
if (right)
{
preorder(right, right_last);
if (left_last)
{
left_last->right = right;
}
last = right_last;
}
}
};
二叉树层次遍历,又称为宽度优先搜索(BFS),按树的层次依次访问树的节点。层次遍历使用队列对遍历节点进行存储,先进入队列的结点,优先遍历拓展其左孩子与右孩子。
class Solution {
public:
void BFS(TreeNode* root) {
queue Q;
Q.push(root);
while (!Q.empty())
{
TreeNode* node = Q.front();
Q.pop();
cout << node->val<left)
{
Q.push(node->left);
}
if (node->right)
{
Q.push(node->right);
}
}
}
};
由此引入下列问题:
突破点:则是记录每一层最后一个节点。
思路: 将层数与节点绑定为pair,压入队列,并记录每一层中出现的最后一个节点,在层次遍历中,每一层遍历到最后一个节点,记录即可。
class Solution {
public:
vector rightSideView(TreeNode* root) {
vector view;
queue> Q;
if (root)
{
Q.push(make_pair(root, 0));
}
while (!Q.empty())
{
TreeNode* node = Q.front().first;
int depth = Q.front().second;
Q.pop();
if (depth == view.size())
{
view.push_back(node->val);
}
else {
view[depth] = node->val;
}
if (node->left)
{
Q.push(make_pair(node->left, depth + 1));
}
if (node->right)
{
Q.push(make_pair(node->right, depth + 1));
}
}
return view;
}
};
预备知识:
图(graph)分为有向图,无向图
图的两个表示方式:
(1) 邻接矩阵
以二维矩阵表示:
#include
using namespace std;
int main()
{
const int MAX_N = 4;
int Graph[MAX_N][MAX_N] = {0};
Graph[0][2] = 1;
Graph[0][4] = 1;
Graph[1][0] = 1;
Graph[1][2] = 1;
Graph[2][3] = 1;
for (int i =0; i
(2) 邻接表
代码:
struct GraphNode
{
int label;
vector neighbors;
GraphNode(int x) : label(x) {};
};
int main()
{
const int MAX_N = 5;
GraphNode *Graph[MAX_N];
for (int i =0; ineighbors.push_back(Graph[2]);
Graph[0]->neighbors.push_back(Graph[4]);
Graph[1]->neighbors.push_back(Graph[0]);
Graph[1]->neighbors.push_back(Graph[2]);
Graph[3]->neighbors.push_back(Graph[3]);
for (int i = 0; i < MAX_N; i++)
{
for (int j = 0; j < Graph[i]->neighbors.size(); j++)
{
cout << Graph[i]->neighbors[j]->label;
}
cout << endl;
}
for (int i = 0; i < MAX_N; i++)
{
delete Graph[i];
}
system("pause");
return 0;
}
图的深度优先遍历(DFS):
struct GraphNode
{
int label;
vector neighbors;
GraphNode(int x) : label(x) {};
};
void DFS_Graph(GraphNode *node, int visit[]) {
visit[node->label] = 1;
cout << node->label << endl;
for (int i = 0; i < node->neighbors.size(); i++) {
if (visit[node->neighbors[i]->label] == 0)
{
DFS_Graph(node -> neighbors[i], visit);
}
}
}
int main()
{
const int MAX_N = 5;
GraphNode *Graph[MAX_N];
for (int i =0; ineighbors.push_back(Graph[2]);
Graph[0]->neighbors.push_back(Graph[4]);
Graph[1]->neighbors.push_back(Graph[0]);
Graph[1]->neighbors.push_back(Graph[2]);
Graph[3]->neighbors.push_back(Graph[3]);
int visit[MAX_N] = { 0 };
for (int i = 0; i < MAX_N; i++)
{
if (visit[i] == 0)
{
DFS_Graph(Graph[i], visit);
}
}
for (int i = 0; i < MAX_N; i++)
{
delete Graph[i];
}
system("pause");
return 0;
}
图的宽度优先遍历:
void BFS_Graph(GraphNode *node, int visit[])
{
queue Q;
Q.push(node);
visit[node->label] = 1;
while (!Q.empty())
{
GraphNode *node = Q.front();
Q.pop();
cout << node->label << endl;
for (int i = 0; i < node->neighbors.size(); i++)
{
if (visit[node->neighbors[i]->label] == 0)
{
Q.push(node->neighbors[i]);
visit[node->neighbors[i]->label] = 1;
}
}
}
}
题目:
问题最终转变成为寻找图中是否有环得问题。有环则不能完成。
思路1:
深度优先搜索:如果某一顶点还未退出该顶点得深度搜索时,又回到了该顶点,证明有环。
struct GraphNode
{
int label;
vector neighbors;
GraphNode(int x) : label(x) {};
};
class Solution {
public:
bool canFinish(int numCourses, vector>& prerequisites) {
vector graph;
vector visit;
for (int i = 0; i < numCourses; i++) {
graph.push_back(new GraphNode(i)); //创建图节点
visit.push_back(-1); // 赋访问状态为空
}
for (int i = 0; i < prerequisites.size(); i++) { // 根据依赖关系创建图节点
GraphNode *begin = graph[prerequisites[i].second];
GraphNode *end = graph[prerequisites[i].first];
begin->neighbors.push_back(end); // 课程2指向课程1
}
for (int i = 0; i < graph.size(); i++) {
if (visit[i] == -1 && !DFS_graph(graph[i], visit)) {
return false; // 如果没有DFS 进行 DFS,遇到环则结束
}
}
for (int i = 0; i < numCourses; i++) {
delete graph[i]; // 依次回收
}
return true; // 返回则可以完成
}
bool DFS_graph(GraphNode *node, vector &visit) {
visit[node->label] = 0; // -1没访问,0正在访问,1已访问
for (int i = 0; i < node->neighbors.size(); i++) {
if (visit[node->neighbors[i]->label] == -1) {
if (DFS_graph(node->neighbors[i], visit) == 0) {
return false;
}
}
else if (visit[node->neighbors[i]->label] == 0) {
return false;
}
}
visit[node->label] = 1;
return true;
}
};
方法二: 拓扑排序(宽度优先搜索)
struct GraphNode
{
int label;
vectorneighbors;
GraphNode(int x) : label(x) {};
};
class Solution {
public:
bool canFinish(int numCourses, vector>& prerequisites) {
vector graph; // 邻接表
vector degree; // 出入度
for (int i = 0; i < numCourses; i++) {
degree.push_back(0);
graph.push_back(new GraphNode(i)); // 初始化
}
for (int i = 0; i < prerequisites.size(); i++) {
GraphNode *begin = graph[prerequisites[i].second];
GraphNode *end = graph[prerequisites[i].first];
begin->neighbors.push_back(end);
degree[prerequisites[i].first]++;
}
queueQ;
for (int i = 0; i < numCourses; i++) {
if (degree[i] == 0) {
Q.push(graph[i]);
}
}
while (!Q.empty())
{
GraphNode *node = Q.front();
Q.pop();
for (int i = 0; i < node->neighbors.size(); i++) {
degree[node->neighbors[i]->label]--;
if (degree[node->neighbors[i]->label] == 0)
{
Q.push(node->neighbors[i]);
}
}
}
for (int i = 0; i < graph.size(); i++) {
delete graph[i];
}
for (int i = 0; i < degree.size(); i++) {
if (degree[i])
{
return false;
}
}
return true;
}
};