leetcode 刷题视频(5) - 二叉树与图

二叉树与图

问题1 路径之和2

Given a binary tree and a sum, find all root-to-leaf paths where each path’s sum equals the given sum.

Note: A leaf is a node with no children.

Example:

Given the below binary tree and sum = 22,

      5
     / \
    4   8
   /   / \
  11  13  4
 /  \    / \
7    2  5   1

Return:

[
   [5,4,11,2],
   [5,8,4,5]
]

链接:https://leetcode-cn.com/problems/path-sum-ii/

思路:

  1. 从根节点深度遍历二叉树,先序遍历时,将该节点值保存至path栈中,使用path_value累加节点值。
  2. 当遍历至叶节点时,检查path_value值是否为sum,若为sum,则将path push进result结果中。
  3. 在后序遍历时,将该节点值从path栈中弹出,path_value减去节点值。
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    explicit TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

class Solution {
public:
    vector<vector<int> > pathSum(TreeNode *root, int sum) {
        vector<vector<int> > result;
        vector<int> path; // 当前路径
        int path_value = 0;
        preoder(root, path_value, sum, path, result);
        return result;
    }

private:
    void preoder(TreeNode *node, int &path_value, int sum, vector<int> &path,
                 vector<vector<int> > &result) {
        if (!node)
            return;
        path_value += node->val;
        path.push_back(node->val);
        if (!node->left && !node->right && path_value == sum) {
            result.push_back(path);
        }
        preoder(node->left, path_value, sum, path, result);
        preoder(node->right, path_value, sum, path, result);
        path_value -= node->val;
        path.pop_back();
    }
};

问题2 最近公共祖先

Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”

Given the following binary tree: root = [3,5,1,6,2,0,8,null,null,7,4]

在这里插入图片描述

Example 1:

Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
Output: 3
Explanation: The LCA of nodes 5 and 1 is 3.

Example 2:

Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
Output: 5
Explanation: The LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition.

Note:

  • All of the nodes’ values will be unique.
  • p and q are different and both values will exist in the binary tree.

链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/

  1. 两个节点的公共祖先一定在从根节点到这两个节点的路径上。

  2. 由于求公共祖先中最近的公共祖先,那么即同时出现在这两条路径上的离根节点最远的节点。

  3. 求p和q节点的路径,两路径上最后一个相同的节点。

问题3 二叉树转链表

Given a binary tree, flatten it to a linked list in-place.

For example, given the following tree:

    1
   / \
  2   5
 / \   \
3   4   6

The flattened tree should look like:

1
 \
  2
   \
    3
     \
      4
       \
        5
         \
          6

链接:https://leetcode-cn.com/problems/flatten-binary-tree-to-linked-list/

在这里插入图片描述

在这里插入图片描述

基础知识 二叉树的层次遍历

广度优先搜索

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x): val(x), left(NULL), right(NULL) {}
};

void BFS_print(TreeNode* root) {
    queue<TreeNode *> Q;
    Q.push(root);
    while (!Q.empty()) {
        TreeNode *node = Q.front();
        Q.pop();
        print(node);
        if (node->left) {
            Q.push(node->left);
        }
        if (node->right) {
            Q.push(node->right);
        }
    }
}

问题4 侧面观察二叉树

Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.

Example:

Input: [1,2,3,null,5,null,4]
Output: [1, 3, 4]
Explanation:

   1            <---
 /   \
2     3         <---
 \     \
  5     4       <---

链接:https://leetcode-cn.com/problems/binary-tree-right-side-view/

在这里插入图片描述

深度优先搜索和广度优先搜索都能解决,深度优先搜索都不需要生成pair,

class Solution {
public:
   vector<int> rightSideView(TreeNode *root) {
       vector<int> result;
       dfs(root, result, 0);
       return result;
   }

private:
   void dfs(TreeNode *root, vector<int> &result, int layer) {
       if (!root) return;
       if (result.size() <= layer) result.push_back(root->val);
       else result[layer] = root->val;
       dfs(root->left, result, layer + 1);
       dfs(root->right, result, layer + 1);
   }
};

广度优先搜索可以不用想上面那样使用pair,可以这样:
先将root push进队列,(队列长度=1)
然后取出root,并添加到result中
然后将root的左右child放入队列(队列长度=2)
取出队列中的两个child,将最后一个child添加到result中,
然后把child的child都添加到队列中(队列长度=4)
取出队列中的4个孙子,将最后一个孙子放到result中,
将8个曾孙放到队列中(队列长度=8)…

class Solution {
public:
   vector<int> rightSideView(TreeNode *root) {
       if (!root) return {};
       queue<TreeNode *> Q;
       Q.push(root);
       vector<int> result;
       while (!Q.empty()) {
           TreeNode *temp;
           int count = Q.size();
           while (count--) {
               temp = Q.front();
               Q.pop();
               if (temp->left)
                   Q.push(temp->left);
               if (temp->right)
                   Q.push(temp->right);
           }
           result.push_back(temp->val);
       }
       return result;
   }
};

问题5 课程安排

There are a total of numCourses courses you have to take, labeled from 0 to numCourses-1.

Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]

Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?

Example 1:

Input: numCourses = 2, prerequisites = [[1,0]]
Output: true
Explanation: There are a total of 2 courses to take. 
             To take course 1 you should have finished course 0. So it is possible.

Example 2:

Input: numCourses = 2, prerequisites = [[1,0],[0,1]]
Output: false
Explanation: There are a total of 2 courses to take. 
             To take course 1 you should have finished course 0, and to take course 0 you should
             also have finished course 1. So it is impossible.

Constraints:

  • The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
  • You may assume that there are no duplicate edges in the input prerequisites.
  • 1 <= numCourses <= 10^5

链接:https://leetcode-cn.com/problems/course-schedule/

思路1 深度优先搜索

在这里插入图片描述

visit[3]=1表示访问过了,0->2->3再遇到3时并没有环,不在同一条链上。visit[*]=0的节点都在一条链上。

struct GraphNode {
    int label;
    vector<GraphNode *> neighbors;
    explicit GraphNode(int x) : label(x) {}
};

class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int> > &prerequisites) {
        vector<GraphNode *> graph;
        vector<int> visit; // 访问状态 -1没有访问 0正在访问 1已访问
        for (int i = 0; i < numCourses; i++) {
            graph.push_back(new GraphNode(i));
            visit.push_back(-1);
        }
        for (auto & prerequisite : prerequisites) {
            GraphNode *begin = graph[prerequisite[1]];
            GraphNode *end = graph[prerequisite[0]];
            begin->neighbors.push_back(end);
        }
        // 以各个起点的图都要判断一遍
        for (int i = 0; i < graph.size(); ++i) {
            if (visit[i] == -1 && !DFS_graph(graph[i], visit)) {
                return false;
            }
        }
        for (int i = 0; i < numCourses; i++) {
            delete graph[i];
        }
        return true;
    }

private:
    // 判断以node为起点的图里面有没有环 true=无环
    bool DFS_graph(GraphNode *node, vector<int> &visit) {
        visit[node->label] = 0;
        for (auto & neighbor : node->neighbors) {
            if (visit[neighbor->label] == -1) {
                if (!DFS_graph(neighbor, visit)) {
                    return false;
                }
            } else if (visit[neighbor->label] == 0) { // 表示邻居就是自己
                return false;
            }
        }
        visit[node->label] = 1;
        return true;
    }
};

为什么把图分成好几块了还是正确的。因为如果有环一定属于同一块。
为什么当return false产生的时候不用把visit改成1,现场应该只出现0或2:
因为一旦出现return false,表明整个算法出结果了,保留不正确的现场也无所谓。
在不执行return false的时候,是一定不会出现visit==0的节点的。所以很安全

思路2 广度优先搜索(拓扑排序)

#include <iostream>
#include <queue>
#include <vector>
using namespace std;

struct GraphNode {
    int label;
    vector<GraphNode *> neighbors;
    explicit GraphNode(int x) : label(x) {}
};

class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int> > &prerequisites) {
        vector<GraphNode *> graph;
        vector<int> degree; // 入度
        for (int i = 0; i < numCourses; ++i) {
            degree.push_back(0);
            graph.push_back(new GraphNode(i));
        }
        for (auto &prerequisite : prerequisites) {
            GraphNode *begin = graph[prerequisite[1]];
            GraphNode *end = graph[prerequisite[0]];
            begin->neighbors.push_back(end);
            degree[end->label]++;
        }
        queue<GraphNode *> Q;
        for (int i = 0; i < numCourses; ++i) {
            if (!degree[i]) {
                Q.push(graph[i]);
            }
        }
        while (!Q.empty()) {
            GraphNode *node = Q.front();
            Q.pop();
            for (auto &neighbor : node->neighbors) {
                degree[neighbor->label]--;
                if (!degree[neighbor->label]) {
                    Q.push(neighbor);
                }
            }
        }
        for (auto &i : graph) {
            delete i;
        }
        for (int i : degree) {
            if (i) {
                return false;
            }
        }
        return true;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值