leetcode 刷題視訊(5) - 二叉樹與圖

Auliegay發表於2020-10-09

二叉樹與圖

問題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]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-0Ph6P8Cj-1602252938434)(https://assets.leetcode.com/uploads/2018/12/14/binarytree.png)]

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/

在這裡插入圖片描述

問題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;
    }
};

思路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;
    }
};

相關文章