首页 > 其他分享 >代码随想录打卡Day18

代码随想录打卡Day18

时间:2024-11-05 22:49:47浏览次数:3  
标签:right TreeNode root 随想录 打卡 NULL Day18 节点 left

1.二叉搜索树的最小绝对差:

题目描述

给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。

差值是一个正数,其数值等于两值之差的绝对值。

示例 1:

输入:root = [4,2,6,1,3]
输出:1

代码:

/**
 * 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:
    TreeNode* per = NULL;
    int result = INT_MAX;
    void traversal(TreeNode* cur) {
        if (cur == NULL) return;

        // 前序遍历
        if (cur->left) traversal(cur->left);

        if (per != NULL) {
            result = min(result, cur->val - per->val);
        }
        per = cur;

        if (cur->right) traversal(cur->right);
    }

    int getMinimumDifference(TreeNode* root) {
        traversal(root);
        return result;
    }
};

2.二叉搜索树中的众数

题目描述:
 

给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。

如果树中有不止一个众数,可以按 任意顺序 返回。

假定 BST 满足如下定义:

  • 结点左子树中所含节点的值 小于等于 当前节点的值
  • 结点右子树中所含节点的值 大于等于 当前节点的值
  • 左子树和右子树都是二叉搜索树

示例 1:

输入:root = [1,null,2,2]
输出:[2]

示例 2:

输入:root = [0]
输出:[0]

代码:

/**
 * 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:
    TreeNode* pre = NULL;
    vector<int> result;
    int count = 0;
    int maxCount = 0;
    void traversal(TreeNode* cur) {
        if (cur == NULL) return;

        // 前序遍历
        traversal(cur->left);

        if (pre == NULL) {
            count = 1;
        }
        else if (cur->val == pre->val) {
            count++;
        }
        else {
            count = 1;
        }
        pre = cur;

        if (count == maxCount) {
            result.push_back(cur->val);
        }

        if (count > maxCount) {
            result.clear();
            maxCount = count;
            result.push_back(cur->val);
        }

        traversal(cur->right);
    }

    vector<int> findMode(TreeNode* root) {
        traversal(root);
        return result;
    }
};

代码逻辑:

 1. 初始化变量
- 'TreeNode pre = NULL;':'pre' 指针用于记录遍历过程中“前一个节点”的指针。
- 'vector<int> result;':'result' 向量用于存储出现频率最高的节点值(即众数)。
- 'int count = 0;':'count' 用于统计当前节点值出现的次数。
- 'int maxCount = 0;':'maxCount' 记录遍历过程中已出现的最高频率。

 2. 中序遍历 'traversal' 函数
函数 'traversal(TreeNode cur)' 使用递归进行中序遍历。二叉搜索树中序遍历会产生有序的节点值,因此遍历时节点值相同的节点会连续出现,便于统计频率。

 遍历逻辑
- 左子树递归:首先递归遍历左子树 ('traversal(cur->left);'),确保以递增顺序访问节点。
  
- 统计逻辑:
  - 如果 'pre == NULL',即当前节点为第一个节点,将 'count' 置为 1。
  - 如果当前节点 'cur->val' 等于 'pre->val',说明这是连续出现的相同值节点,增加 'count'。
  - 如果 'cur->val' 与 'pre->val' 不同,说明出现了新的值,将 'count' 重置为 1。
  - 将 'cur' 更新为 'pre',用于下一个节点的比较。
  
- 更新结果:
  - 如果 'count == maxCount',说明当前值的频率和 'maxCount' 相同,将该值加入 'result'。
  - 如果 'count > maxCount',更新 'maxCount' 为 'count',并清空 'result',只保留当前值为新众数。

- 右子树递归:递归遍历右子树 ('traversal(cur->right);') 完成中序遍历。

 3. 主函数 'findMode'
- 调用 'traversal(root);' 进行中序遍历。
- 最后返回 'result',其中包含所有出现频率最高的值。

- 代码使用中序遍历和计数变量,有效识别树中所有众数。
- 'count' 和 'maxCount' 动态更新频率,'result' 保存当前最高频次的节点值。
- 这种方法节省了空间和时间,使其能够在线性时间复杂度内找到众数。

3.二叉树的最近公共祖先

题目描述:

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

示例 1:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。

示例 2:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。

示例 3:

输入:root = [1,2], p = 1, q = 2
输出:1

代码:

/**
 * 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:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        // 终止条件
        if (root == NULL) return NULL;
        if (root == p || root == q) return root;

        // 后续遍历
        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right = lowestCommonAncestor(root->right, p, q);

        if (left != NULL && right != NULL) return root;
        if (left != NULL && right == NULL) return left;
        if (right != NULL && left == NULL) return right;

        else {
            return NULL;
        } 
    }
};

代码逻辑:


1. 终止条件:
   '''cpp
   if (root == NULL) return NULL;
   if (root == p || root == q) return root;
   '''
   - 当 'root' 为 'NULL' 时,返回 'NULL' 表示该路径不存在有效节点。
   - 如果当前节点 'root' 是 'p' 或 'q',则返回 'root',表示找到了其中一个目标节点,开始向上返回。

2. 递归查找左右子树:
   '''cpp
   TreeNode left = lowestCommonAncestor(root->left, p, q);
   TreeNode right = lowestCommonAncestor(root->right, p, q);
   '''
   - 通过递归调用在左子树和右子树分别寻找 'p' 和 'q',将返回的结果分别保存在 'left' 和 'right'。

3. 判断左右子树结果:
   '''cpp
   if (left != NULL && right != NULL) return root;
   if (left != NULL && right == NULL) return left;
   if (right != NULL && left == NULL) return right;
   '''
   - 如果 'left' 和 'right' 都不为空,说明 'p' 和 'q' 分别位于当前节点 'root' 的左右子树上,那么 'root' 就是最近公共祖先,返回 'root'。
   - 如果只有 'left' 不为空,说明 'p' 和 'q' 都在左子树上,返回 'left'。
   - 如果只有 'right' 不为空,说明 'p' 和 'q' 都在右子树上,返回 'right'。

4. 返回空结果:
   '''cpp
   else {
       return NULL;
   }
   '''
   - 如果 'left' 和 'right' 都为空,则返回 'NULL',表示在当前路径未找到任何一个目标节点。

 总结
- 该算法使用了后序遍历的思想,即先递归遍历子树,再处理根节点。
- 通过逐层返回找到的节点,代码可以在找到公共祖先后立即返回,不必遍历整棵树。
- 时间复杂度为 \(O(N)\),其中 \(N\) 是节点数,适合于不保证树是二叉搜索树的情况。

标签:right,TreeNode,root,随想录,打卡,NULL,Day18,节点,left
From: https://blog.csdn.net/jianbaigreat/article/details/143529294

相关文章

  • 代码随想录打卡Day17
    1.力扣954:最大二叉树:题目描述:给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:创建一个根节点,其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树。递归地在最大值 右边 的 子数组后缀上 构建右......
  • 代码随想录打卡Day16
    1.力扣531:找树左下角的值。题目描述:给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。假设二叉树中至少有一个节点。示例1:输入:root=[2,1,3]输出:1示例2:输入:[1,2,3,4,null,5,6,null,null,7]输出:7解答代码:/***Defi......
  • 代码随想录算法训练营第十六天|leetcode513.找树左下角的值、leetcode112.路径总和、l
    1leetcode513.找树左下角的值题目链接:513.找树左下角的值-力扣(LeetCode)文章链接:代码随想录视频链接:怎么找二叉树的左下角?递归中又带回溯了,怎么办?|LeetCode:513.找二叉树左下角的值_哔哩哔哩_bilibili思路:就是用一个东西存储result,使用后续遍历,如果遇到了最深的那一个值,就......
  • python+flask计算机毕业设计高校学生课堂考勤打卡APP的设计和实现(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、选题背景关于高校学生课堂考勤的研究,现有研究多集中在传统点名方式的改进以及基于单一技术的考勤系统开发。例如,有的研究专注于利用蓝牙技术实......
  • python+flask计算机毕业设计好骑行打卡园app系统(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容好骑行打卡园app系统毕业设计相关内容一、选题背景关于骑行打卡类APP的研究,现有研究主要以骑行记录和路线规划为主,专门针对骑行打卡园这种集打卡......
  • 代码随想录算法训练营第十四天|leetcode226. 翻转二叉树、leetcode101.对称二叉树、le
    1leetcode226.翻转二叉树题目链接:226.翻转二叉树-力扣(LeetCode)文章链接:代码随想录视频链接:听说一位巨佬面Google被拒了,因为没写出翻转二叉树|LeetCode:226.翻转二叉树哔哩哔哩bilibili自己的思路:之前想过就是使用层序遍历的方法来做这一道题目,后来感觉有一些行不通,就......
  • 代码随想录算法训练营第十三天|二叉树的理论基础、二叉树的递归遍历、二叉树的层序遍
    1二叉树的理论基础文章链接:代码随想录视频链接:关于二叉树,你该了解这些!|二叉树理论基础一网打尽,二叉树的种类、二叉树的存储方式、二叉树节点定义、二叉树的遍历顺序哔哩哔哩bilibili1.1二叉树的种类满二叉树所有节点处的值都排满了,没有空的完全二叉树只有在最后......
  • 代码随想录之哈希表刷题总结
    1.哈希表理论基础哈希表-(hashtable),数组其实就是一张哈希表,哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素。如下图:1.1哈希函数把学生的姓名直接映射为哈希表上的索引,然后就可以通过查询索引下标快速知道这位同学是否在这所学校里了。哈希函数如下图......
  • 考研打卡(9)
    开局(9)开始时间 2024-11-0513:57:18结束时间 2024-11-05 14:26:41今天要去打剧本杀数据结构将一个n*n的对称矩阵A的下三角按行存放在一堆数组B中,A[0][0]存放在B[0][0]中,那么第i行的对角元素A[i][i]在B中的存放位置是____(湖南大学2012)A(i+3)*i/2B(i+1)*i/2C(2......
  • 代码随想录算法训练营day34 day36| 卡码网46题.01背包 416.分割等和子集 1049. 最后
    学习资料:https://programmercarl.com/背包理论基础01背包-1.html动态规划01背包问题学习记录:卡码网46题.01背包点击查看代码##二维背包解法#n,bagweight=map(int,input().split())#weight=list(map(int,input().split()))#value=list(map(int,input().sp......