剑指offer 第15天 搜索与回溯算法(中等)C++题解

一、二叉树中和为某一值的路径

剑指 Offer 34. 二叉树中和为某一值的路径icon-default.png?t=M85Bhttps://leetcode.cn/problems/er-cha-shu-zhong-he-wei-mou-yi-zhi-de-lu-jing-lcof/

给你二叉树的根节点 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;
    }
};

二、二叉搜索树与双向链表

剑指 Offer 36. 二叉搜索树与双向链表icon-default.png?t=M85Bhttps://leetcode.cn/problems/er-cha-sou-suo-shu-yu-shuang-xiang-lian-biao-lcof/

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。

为了让您更好地理解问题,以下面的二叉搜索树为例:

我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。

下图展示了上面的二叉搜索树转化成的链表。“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大节点icon-default.png?t=M85Bhttps://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);
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨小木木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值