目录
113.路径之和II
思考:进行递归查找路径的时候,什么时候跳出递归?
答:如果遍历至空指针,结束。
什么时候添加路径呢?为叶子结点,并且路径值和要求的和值相同。
class Solution {
public:
vector<vector<int>> pathSum(TreeNode* root, int sum) {
vector<int> path;
int path_val=0;
vector<vector<int>> result;
preOrder(root, path_val, sum, path, result);
return result;
}
void preOrder(TreeNode* node,
int &path_val, int sum,
vector<int> &path,
vector<vector<int>>& result) {
if (!node) return;
path.push_back(node->val);
path_val += node->val;
if (!node->left && !node->right && path_val == sum) {
result.push_back(path);
}
preOrder(node->left, path_val, sum, path, result);
preOrder(node->right, path_val, sum, path, result);
path.pop_back();
path_val -= node->val;
}
};
236.二叉树的最近公共祖先
思考:找到两个节点的最近公共祖先,因为二叉树的结构性,他都是从一个节点伸展出来的各个路径,所以要找到节点p,q的公共最近祖先,只需要到p,q的两条路径,然后像找相交链表的公共节点(leetcode 160)一样,一步步回退回去查找到第一个相同的节点,这里和上一题求所有路径值为sum的题目不同在于,这里只是查找到p这个节点的路径,所以只要找到了就可以设置一个标记变量finish直接退出查找就可以了。
1、跳出循环的条件,当前节点为空或者finish==1
2、得到两个路径,向后pop_back(),知道两个路径相等,然后查找是否是相同的节点。
3、和上题不同在于上一题是值,这一题是节点指针;上一题是所有路径,这一题是单一路径,所有设置一个finish标志。
查找某个节点的路径:
void preorder(TreeNode* node,
TreeNode *search,
std::vector<TreeNode*> &path,
std::vector<TreeNode*> &result,
int &finish) {
if (!node||finish) {
return;
}
path.push_back(node);
if (node == search) {
finish = 1;
result = path;
}
preorder(node->left, search, path, result, finish);
preorder(node->right, search, path, result, finish);
path.pop_back();
}
整体代码:
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
int finish = 0;
vector<TreeNode*> path;
vector<TreeNode*> result1;
vector<TreeNode*> result2;
preorder(root, p, path, result1, finish);
finish = 0;
preorder(root, q, path, result2, finish);
while (result1.size() > result2.size()) {
result1.pop_back();
}
while (result2.size() > result1.size()) {
result2.pop_back();
}
while (result1.back() != result2.back()) {
result1.pop_back();
result2.pop_back();
}
return result1.back();
}
void preorder(TreeNode* node,
TreeNode *search,
std::vector<TreeNode*> &path,
std::vector<TreeNode*> &result,
int &finish) {
if (!node||finish) {
return;
}
path.push_back(node);
if (node == search) {
finish = 1;
result = path;
}
preorder(node->left, search, path, result, finish);
preorder(node->right, search, path, result, finish);
path.pop_back();
}
};
114.二叉树展开为链表
思考:
1、二叉树和链表的存储结构相比,只多了一个指针。题中整理的链表为二叉树的先序遍历,只需要将二叉树的左子树整理成单链表,右子树整理成单链表,然后左子树最后的一个节点指针指向右子树的第一个指针,所以存储信息的时候还应该包含一个last指针。
2、在前序遍历的时候,相当于分治算法的最小一个子问题,就是访问到叶子节点,此时把last = node;
3、如果存在左子树,中序遍历的时候,把当前的node->left = NULL;node->right = left_last;(当前节点的下一个应该是左子树的最后一个结点),并且记录下last = left_last(因为可能右子树为空,所以临时保存last指针)
4、如果存在右子树,后序遍历的时候,若存在左子树,把左子树最后一个节点拼接到右子树的首部(left_last = right),之后再输出last = right_last;
5、设置最后一个节点指针的原因,若1->2->3->4...只是很深的树的一小部分,1不是根节点,就必须把这小部分的最后一个节点指针传出去,完成递归。
6、什么时候对节点判空?感觉应该在flatten(TreeNode* )就判断比较好。若传入的就是空节点,直接返回。
/**
* 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:
void flatten(TreeNode* root) {
if(!root){
return;
}
TreeNode* last = NULL;
preorde(root,last);
}
void preorde(TreeNode* node,TreeNode* &last){
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){
preorde(left,left_last);
node->left = NULL;
node->right = left;
last = left_last;
}
if(right){
preorde(right,right_last);
if(left){
left_last->right = right;
}
last = right_last;
}
}
};
207.课程表(图)
图的基础数据结构:
struct GraphNode{
int label;//标识图的哪个节点
vector<GraphNode*> negihbors;//节点的领接表
};
图的深度优先遍历,广度优先遍历:
TIPS:需要一个标识符visit来存储每个节点是否被访问过了,只有没有被访问的才需要搜索。
深度优先遍历,从某个节点出发,一直深度搜索,当所有领接节点都搜索完毕之后,再搜索下一个节点,直到图中所有节点都搜索完毕。
广度优先遍历:通过一个queue队列,来存储图的某个节点,然后先搜索它领接的所有节点,然后再将新搜索到的节点给存入队列,不断的进行搜索,直到所有节点搜索完毕。
思考:
1、首先构建有向图,根据pair关系。
2、一般的visit只有两个状态,访问完成或者未访问。但是这里需要一个visit = 0,第三中状态代表正在被访问。因为只有正在被访问的时候,经过的路径途中的点会被标注成0,要是此时遇到一个还没有访问的领节点,但是已经正在被访问,说明其中是有环的。
3、有环的情况有分为两种,一种是1->2->3->1,正好找到的就是环上的节点;另一种1->2->3->2,从这个节点出发,经过了一个环。
根据深度优先结果:
struct GraphNode{
int label;
vector<GraphNode*> neighbors;
GraphNode(int x):label(x){};
};
bool DFS_Graph(GraphNode* node, vector<int>& visit) {
visit[node->label] = 0;
for (auto i : node->neighbors) {
if (visit[i->label] == 0) {
return false;
}
else if (visit[i->label] == -1 && !DFS_Graph(i, visit)) {
return false;
}
}
visit[node->label] = 1;
return true;
}
class Solution {
public:
bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
//1构图
//GraphNode* Graph[numCourses]; /*表达式必须含有常量值*/
vector<GraphNode*> Graph;
//vector<int> visit(5,-1); //节点的状态访问 -1:没有访问过 0:正在访问 1 :已经访问过了
vector<int> visit;
for (int i = 0; i < numCourses; i++) {
Graph.push_back( new GraphNode(i));
visit.push_back(-1);
}
for (auto i : prerequisites) {
//auto begin = i.first;
auto begin = Graph[i.second];
auto end = Graph[i.first];
//Graph[begin]->neighbors.push_back(endNode);
begin->neighbors.push_back(end);
}
for (int i = 0; i < numCourses; i++) {
if (visit[i] == -1&&!DFS_Graph(Graph[i],visit)) {
return false;
}
}
return true;
}
};
根据广度优先结果:
广度优先搜索解题根据入度,若一个节点在环上,那么它的入度肯定不会为0,所以先选择入度为0的点,把他们加入到队列之中,然后将它的所有领接点的入度都减去1,再进行把下一个入度为0的点加入队列,继续搜索...如果到最后图中所有点的入度都为0,则不存在环,否则就存在环。
struct GraphNode{
int label;
vector<GraphNode*> neighbors;
GraphNode(int x ):label(x){};
};
class Solution {
public:
bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
//1构图
vector<GraphNode*> Graph;
vector<int > indegree;
for(int i = 0; i <numCourses;i++){
Graph.push_back(new GraphNode(i));
indegree.push_back(0);
}
//确定节点直接领接关系
for(auto i : prerequisites){
auto end = i.first;
auto begin = i.second;
Graph[begin]->neighbors.push_back( Graph[end]);
indegree[end]++;
}
//把入度为0的节点传入队列Q之中
queue<GraphNode*> Q;
for(int i = 0; i <indegree.size();i++){
if(indegree[i]==0){
Q.push(Graph[i]);
}
}
while(!Q.empty()){
auto temp = Q.front();
Q.pop();
//写成了temp,就显示“基于此范围的for语句需要begin函数”,因为不是迭代器,temp 是GraphNode*的指针
//应该是他的领接点temp->neighbors,整好也是vector,有begin和end迭代器
for(auto i : temp->neighbors){
indegree[i->label]--;
if(indegree[i->label]==0){
Q.push(i);
}
}
}
for(auto i : indegree){
if(i){
return false;
}
}
return true;
}
};