一、二叉树中和为某一值的路径
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。
示例 1:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]
示例 2:
输入:root = [1,2,3], targetSum = 5
输出:[]
示例 3:
输入:root = [1,2], targetSum = 0
输出:[]
提示:
树中节点总数在范围 [0, 5000] 内
-1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000
注意:本题与主站 113 题相同:https://leetcode-cn.com/problems/path-sum-ii/
解题思路:
1.深度优先搜索+回溯可以解决此类问题。
2.深度优先搜索根据前序遍历,先访问根节点,再依次访问左子节点和右子节点。
3.回溯记录所有路径将符合条件的路径加入到结果集中。
具体细节:
1.确定回溯递归函数的参数:记录路径的数组path,记录结果集的数组result,当前节点cur,以及目标和sum。
2.确定回溯递归函数的终止条件:当路径和等于目标值时将路径数组path加入到结果集result当中。
3.将当前节点加入到路径数组path之中,同时递归左子节点和右子节点。
4.进行回溯,将路径数组中的当前节点弹出。
5.返回结果集。
复杂度分析:
1.时间复杂度:遍历二叉树所有节点,O(N)。
2.空间复杂度:最差情况需要存储所有节点,O(N)。
代码实现:
/**
* 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<vector<int>> pathSum(TreeNode* root, int target) {
vector<vector<int>> result;
if (root == nullptr) return result;
vector<int> path;
int sum = 0;
backtracking(result, path, root, sum, target);
return result;
}
void backtracking(vector<vector<int>> &result, vector<int> &path, TreeNode* cur, int sum, int target) {
path.push_back(cur -> val);
sum += cur -> val;
if (sum == target && cur -> left == nullptr && cur -> right == nullptr) {
result.push_back(path);
}
if (cur -> left) backtracking(result, path, cur -> left, sum, target);
if (cur -> right) backtracking(result, path, cur -> right, sum, target);
path.pop_back();
sum -= cur -> val;
}
};
二、二叉搜索树与双向链表
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
注意:本题与主站 426 题相同:https://leetcode-cn.com/problems/convert-binary-search-tree-to-sorted-doubly-linked-list/
注意:此题对比原题有改动。
解题思路:
1.二叉搜索树的中序遍历是有序的,因此可以想到采用中序遍历的方法,即左子节点,当前节点,右子节点的顺序。
2.前驱节点的右指针指向当前节点,当前节点的左指针指向前驱节点,前驱指向当前节点,循环往复便可构成双向链表。
3.将头节点和尾节点相连则构成了循环双向链表。
具体细节:
1.初始化全局节点前驱节点和头节点pre,head。
2.中序遍历树:左递归,处理当前节点,右递归。
3.处理当前节点:前驱的右指针指向当前节点,当前节点的左指针指向前驱节点,前驱更新到当前节点。
4.特殊处理头节点即当前驱节点为空时,当前节点即为头节点。
复杂度分析:
1.时间复杂度:中序遍历访问所有节点,O(N)。
2.空间复杂度:最差情况即树为链表,递归深度为N,O(N)。
代码实现:
/*
// 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* pre = NULL;
Node* head = NULL;
Node* treeToDoublyList(Node* root) {
if (root == NULL) return NULL;
dfs(root);
head -> left = pre;
pre -> right = head;
return head;
}
void dfs(Node* cur) {
if (cur == NULL) return;
dfs(cur -> left);
if (pre) pre -> right = cur;
else head = cur;
cur -> left = pre;
pre = cur;
dfs(cur -> right);
}
};
三、二叉搜索树的第k大节点
剑指 Offer 54. 二叉搜索树的第k大节点https://leetcode.cn/problems/er-cha-sou-suo-shu-de-di-kda-jie-dian-lcof/
给定一棵二叉搜索树,请找出其中第 k 大的节点的值。
示例 1:
输入: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
2
输出: 4
示例 2:
输入: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \
3 6
/ \
2 4
/
1
输出: 4
限制:
1 ≤ k ≤ 二叉搜索树元素个数
解题思路:
1.二叉搜索树的中序遍历是有序的,故只需中序遍历一遍即可获得有序数组。
2.这里求第k大个数故只需先访问右子节点,根节点,左子节点的顺序即可。
具体细节:
1.初始化递归参数:当前节点cur,当前位置i,目标位置k。
2.按照右子节点,当前节点,左子节点的顺序递归遍历。
3.当当前位置等于目标位置时返回即可。
复杂度分析:
1.时间复杂度:最差情况二叉搜索树是一个链表,O(N)。
2.空间复杂度:最差情况栈的深度为N,O(N)。
代码实现:
/**
* 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:
int kthLargest(TreeNode* root, int k) {
int result = 0;
int i = 0;
midtrans(root, result, i, k);
return result;
}
void midtrans(TreeNode* root, int & result, int & i, int k) {
if (root == NULL) return;
midtrans(root -> right, result, i, k);
i++;
if (i == k) result = root -> val;
midtrans(root -> left, result, i, k);
}
};