Leetcode hot 100(day 4)

翻转二叉树

做法:递归即可,注意判断为空


class Solution {
public:TreeNode* invertTree(TreeNode* root) {if(root==nullptr)return nullptr;TreeNode* node=root->left;root->left=invertTree(root->right);root->right=invertTree(node);return root;}
};

对称二叉树

做法一:递归。使用两个不同的指针进入递归即可


class Solution {
public:bool check(TreeNode* p,TreeNode* q){if(!p&&!q)return true;if(!p||!q)return false;return p->val==q->val&&check(p->left,q->right)&&check(p->right,q->left);}bool isSymmetric(TreeNode* root) {return check(root->left,root->right);}
};

做法二:迭代。一开始想用deque,但卡在了迭代怎么能让同一层进行比较,后面看了题解才知道可以直接用queue,只要压入的时候保证顺序即可


class Solution {
public:bool check(TreeNode* u, TreeNode* v) {queue<TreeNode*> q;q.push(u);q.push(v);while(!q.empty()){u=q.front();q.pop();v=q.front();q.pop();if(!u&&!v)continue;if((!u||!v)||(u->val!=v->val))return false;q.push(u->left);q.push(v->right);q.push(u->right);q.push(v->left);}return true;}bool isSymmetric(TreeNode* root) {return check(root->left,root->right);}
};

二叉树的直径

做法:一开始想用树形dp,但发现搞复杂了根本不用。其实最直观的思想就是,对每个节点依次遍历,然后求左子树和右子树深度,然后进行比较。但我们可以发现,在这一过程中,重复搜索了很多地方。要么记忆化搜索,要么就直接在递归中比较即可,这样就只需要递归一次。


class Solution {
public:int ans=0;int depth(TreeNode* root){if(root==nullptr)return 0;int L=depth(root->left);int R=depth(root->right);ans=max(ans,L+R+1);return max(L,R)+1;}int diameterOfBinaryTree(TreeNode* root) {depth(root);return ans-1;}
};

二叉树的层序遍历

做法一:迭代,BFS,记录一下每层的节点个数即可


class Solution {
public:vector<vector<int>> levelOrder(TreeNode* root) {if(root==nullptr)return {};vector<vector<int>> vec;queue<TreeNode*>q;q.push(root);while(!q.empty()){vector<int> v;int sz=q.size();for(int i=1;i<=sz;i++){auto u=q.front();q.pop();if(u->left!=nullptr)q.push(u->left);if(u->right!=nullptr)q.push(u->right);v.emplace_back(u->val);}vec.emplace_back(v);}        return vec;}
};

做法二:递归,这个想法很精妙


class Solution {
private:vector<vector<int>> ret;
public:vector<vector<int>> levelOrder(TreeNode* root) {dfs(root,0);return ret;}void dfs(TreeNode* root,int deep){if(root == nullptr) return;if(deep>=ret.size()) ret.push_back({root->val});else ret[deep].push_back(root->val);dfs(root->left,deep+1);dfs(root->right,deep+1);}
};

将有序数组转换为二叉搜索树

做法:每次建立中间节点即可,然后递归建立树


class Solution {
public:TreeNode* build(vector<int>& nums,int left,int right){if(left>right)return nullptr;int mid=(left+right)>>1;TreeNode* root=new TreeNode(nums[mid]);root->left=build(nums,left,mid-1);root->right=build(nums,mid+1,right);return root;}TreeNode* sortedArrayToBST(vector<int>& nums) {return build(nums,0,nums.size()-1);}};

验证二叉搜索树

做法一:分别dfs两边的子树,如果不满足条件就返回false


class Solution {
public:bool dfs(TreeNode* root,long long lower,long long upper){if(root==nullptr)return true;if(root->val<=lower||root->val>=upper)return false;return dfs(root->left,lower,root->val)&&dfs(root->right,root->val,upper);}bool isValidBST(TreeNode* root) {return dfs(root,LONG_MIN,LONG_MAX);}
};

做法二:中序遍历。这里可以递归或者不递归都可以


class Solution {
public:vector<int> vec;bool flag=true;void dfs(TreeNode* root){if(root==nullptr)return;dfs(root->left);if(vec.size()&&vec.back()>=root->val){flag=false;return;}vec.emplace_back(root->val);dfs(root->right);}bool isValidBST(TreeNode* root) {dfs(root);return flag;}
};

二叉搜索树中第k小的元素

做法一:非优化。简单直接的中序遍历,刚好练一下非递归


class Solution {
public:int kthSmallest(TreeNode* root, int k) {int cnt=0;stack<TreeNode*> s;while(root!=nullptr||!s.empty()){if(root!=nullptr){s.push(root);root=root->left;}else{root=s.top();s.pop();cnt++;if(cnt==k)return root->val;root=root->right;}}return -1;}
};

做法二:如果要频繁访问第k小的数字,可以通过预处理节点数,有点类似快排找第k个大的


class Solution {
public:unordered_map<TreeNode*,int>nodenum;int countnodenum(TreeNode* node){if(node==nullptr)return 0;nodenum[node]=1+countnodenum(node->left)+countnodenum(node->right);return nodenum[node];}int getnodenum(TreeNode* node){if(node!=nullptr&&nodenum.count(node)){return nodenum[node];}return 0;}int kthSmallest(TreeNode* root, int k) {countnodenum(root);while(root!=nullptr){int left=getnodenum(root->left);if(left<k-1){root=root->right;k-=left+1;}else if(left==k-1)break;else root=root->left;}    return root->val;}
};

二叉树的右视图

做法一:迭代,广度优先遍历即可


class Solution {
public:vector<int> rightSideView(TreeNode* root) {if(root==nullptr)return {};queue<TreeNode*> q;vector<int> vec;q.push(root);while(!q.empty()){int sz=q.size();for(int i=1;i<sz;i++){TreeNode* cur=q.front();q.pop();if(cur->left)q.push(cur->left);if(cur->right)q.push(cur->right);}TreeNode* cur=q.front();q.pop();if(cur->left!=nullptr)q.push(cur->left);if(cur->right!=nullptr)q.push(cur->right);vec.emplace_back(cur->val);}return vec;}
};

做法二:递归,其实就和二叉树层序遍历那题一样


class Solution {
public:void bst(TreeNode* node,vector<int>& ans,int depth){if(!node)return;if(depth>ans.size())ans.push_back(node->val);bst(node->right,ans,depth+1);bst(node->left,ans,depth+1);}vector<int> rightSideView(TreeNode* root) {if(!root)return {};vector<int> ans;bst(root,ans,1);return ans;}
};

二叉树展开为链表

做法一:按照前序遍历的顺序来构造链表,所以先进行一次前序遍历,然后用一个vector存下来所有的节点。然后逐步遍历设置即可


class Solution {
public:void preorder(TreeNode* root,vector<TreeNode*> &vec){if(root){vec.emplace_back(root);preorder(root->left,vec);preorder(root->right,vec);}}void flatten(TreeNode* root) {vector<TreeNode*> vec;preorder(root,vec);int n=vec.size();for(int i=1;i<n;i++){TreeNode* prev=vec[i-1],*cur=vec[i];prev->left=nullptr;prev->right=cur;}}
};

做法二:空间复杂度O(1),对于一个节点,如果左子节点为空,则不需要操作,如果不为空,那么对于右边,要找到左子树最右的节点,把右节点连接上去,然后再把左子树连到右边即可。非常巧妙的做法


class Solution {
public:void flatten(TreeNode* root) {TreeNode* cur=root;while(cur!=nullptr){if(cur->left!=nullptr){auto next=cur->left;auto predecessor=next;while(predecessor->right!=nullptr)predecessor=predecessor->right;predecessor->right=cur->right;cur->left=nullptr;cur->right=next;}cur=cur->right;}}
};

从前序与中序遍历序列构造二叉树

做法一:递归,前序遍历第一个节点是根节点,中序遍历则是[左子树,根节点,右子树],我们可以先根据前序定位根节点,然后根据中序才能知道哪些在左边,哪些在右边。递归构建即可


class Solution {
public:unordered_map<int,int> mp;TreeNode* build(vector<int>& preorder,vector<int>& inorder,int pl,int pr,int il,int ir){if(pl>pr)return nullptr;int p_root=pl;int in_root=mp[preorder[p_root]];TreeNode* root=new TreeNode(preorder[p_root]);int sz_l=in_root-il;root->left=build(preorder,inorder,pl+1,pl+sz_l,il,in_root-1);root->right=build(preorder,inorder,pl+sz_l+1,pr,in_root+1,ir);return root;}TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {int n=preorder.size();for(int i=0;i<n;i++){mp[inorder[i]]=i;}return build(preorder,inorder,0,n-1,0,n-1);}
};

做法二:迭代 先放养,因为肯定会忘记


路径总和III

做法一:直接遍历每个节点,对每个节点dfs看有几个满足的路径


class Solution {
public:int rootsum(TreeNode* root,long long target){if(!root)return 0;int ans=0;if(root->val==target)ans++;ans+=rootsum(root->left,target-root->val);ans+=rootsum(root->right,target-root->val);return ans;}int pathSum(TreeNode* root, long long targetSum) {if(!root)return 0;int ans=rootsum(root,targetSum);ans+=pathSum(root->left,targetSum);ans+=pathSum(root->right,targetSum);return ans;}
};

做法二:可以利用前缀和,用哈希表将对应前缀和和数量对应起来。如果遍历到某一前缀和,前缀和-target的数量就是目前路径的总和为target的线路。要记得遍历前哈希加1,递归后面要减去1


class Solution {
public:unordered_map<long long,int> pre;int dfs(TreeNode *root,long long cur,int target){if(!root)return 0;int ans=0;cur+=root->val;if(pre.count(cur-target)){ans=pre[cur-target];//哈希表存储对应值有几个}pre[cur]++;ans+=dfs(root->left,cur,target);ans+=dfs(root->right,cur,target);pre[cur]--;//因为遍历完左右子树就不存在这个前缀和了return ans;}int pathSum(TreeNode* root, int targetSum) {pre[0]=1;return dfs(root,0,targetSum);}
};

二叉树的最近公共祖先 想起数链剖分了

做法一:哈希表


class Solution {
public:unordered_map<int,TreeNode*>fa;unordered_map<int,bool>vis;void dfs(TreeNode* root){if(root->left){fa[root->left->val]=root;dfs(root->left);}if(root->right){fa[root->right->val]=root;dfs(root->right);}}TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {fa[root->val]=nullptr;dfs(root);while(p!=nullptr){vis[p->val]=true;p=fa[p->val];}while(q!=nullptr){if(vis[q->val])return q;q=fa[q->val];}return nullptr;}
};

二叉树中的最大路径和

做法:由于不能向上面走,所以不是树形dp。只需要递归即可。对于空节点,那么就是贡献度为0,递归的时候,要比较,该节点加左子树和右子树的和是否大于maxum,返回的不是和而是节点值加上max(left,right),因为每个节点至多只出现一次


class Solution {
public:int maxSum=INT_MIN;int maxsum(TreeNode* root){if(!root)return 0;int sum=root->val;int leftsum=maxsum(root->left);int rightsum=maxsum(root->right);//maxSum=max(maxSum,leftsum);//maxSum=max(maxSum,rightsum);if(leftsum>0)sum+=leftsum;else leftsum=0;if(rightsum>0)sum+=rightsum;else rightsum=0;maxSum=max(maxSum,sum);return root->val+max(leftsum,rightsum);}int maxPathSum(TreeNode* root) {maxsum(root);return maxSum;}
};

岛屿数量

做法一:深度优先遍历,搜寻到一个节点,我们可以dfs周边满足条件的节点,这样就能把一整个岛屿全部化为海水。dfs了几次就代表有几个岛屿

class Solution {
public:void dfs(vector<vector<char>>& grid,int r,int c){int nr=grid.size();int nc=grid[0].size();grid[r][c]='0';if(r-1>=0&&grid[r-1][c]=='1')dfs(grid,r-1,c);if(r+1<nr&&grid[r+1][c]=='1')dfs(grid,r+1,c);if(c-1>=0&&grid[r][c-1]=='1')dfs(grid,r,c-1);if(c+1<nc&&grid[r][c+1]=='1')dfs(grid,r,c+1);}int numIslands(vector<vector<char>>& grid) {int nr=grid.size();if(!nr)return 0;int nc=grid[0].size();int num=0;for(int r=0;r<nr;r++)for(int c=0;c<nc;c++){if(grid[r][c]=='1'){num++;dfs(grid,r,c);}}return num;}
};

做法二:BFS其实差不多,也是加入pair组成的队列

做法三:好像能用并查集吧 我不会


腐烂的橘子

做法:BFS

class Solution {
public:int cnt;int dis[10][10];int dir_x[4]={0,1,0,-1};int dir_y[4]={1,0,-1,0};int orangesRotting(vector<vector<int>>& grid) {queue<pair<int,int>>q;cnt=0;int n=grid.size();int m=grid[0].size();for(int i=0;i<n;i++)for(int j=0;j<m;j++){if(grid[i][j]==2){q.push({i,j});//dis[i][j]=0;}else if(grid[i][j]==1){cnt++;}}if(q.empty()&&cnt)return -1;int ans=0;while(!q.empty()){int t=q.size();for(int k=0;k<t;k++){pair<int,int> p=q.front();q.pop();for(int i=0;i<4;i++){int x=p.first+dir_x[i];int y=p.second+dir_y[i];if(x>=0&&x<n&&y>=0&&y<m&&grid[x][y]==1){grid[x][y]=2;q.push({x,y});cnt--;}}}if(!q.empty())ans++;}if(cnt)return -1;return ans;}
};

课程表

做法一:拓扑排序

class Solution {
public:int du[2010];unordered_map<int,vector<int>>mp;bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {for(auto cur:prerequisites){du[cur[1]]++;mp[cur[0]].push_back(cur[1]);}queue<int> q;for(int i=0;i<numCourses;i++){if(du[i]==0)q.push(i);}while(!q.empty()){int u=q.front();q.pop();numCourses--;for(auto num:mp[u]){du[num]--;if(du[num]==0)q.push(num);}}if(numCourses==0)return true;return false;}
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/75426.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C,C++语言缓冲区溢出的产生和预防

缓冲区溢出的定义 缓冲区是内存中用于存储数据的一块连续区域&#xff0c;在 C 和 C 里&#xff0c;常使用数组、指针等方式来操作缓冲区。而缓冲区溢出指的是当程序向缓冲区写入的数据量超出了该缓冲区本身能够容纳的最大数据量时&#xff0c;额外的数据就会覆盖相邻的内存区…

大数据(4)Hive数仓三大核心特性解剖:面向主题性、集成性、非易失性如何重塑企业数据价值?

目录 背景&#xff1a;企业数据治理的困境与破局一、Hive数据仓库核心特性深度解析1. ‌面向主题性&#xff08;Subject-Oriented&#xff09;&#xff1a;从业务视角重构数据‌2. ‌集成性&#xff08;Integrated&#xff09;&#xff1a;打破数据孤岛的统一视图‌3. ‌非易失…

A股复权计算_前复权数据计算_终结章

目录 前置&#xff1a; 计算方法推导 数据&#xff1a; 代码&#xff1a; 视频&#xff1a; 前置&#xff1a; 1 本系列将以 “A股复权计算_” 开头放置在“随想”专栏 2 权息数据结合 “PostgreSQL_” 系列博文中的股票未复权数据&#xff0c;可以自行计算复权日数据 …

Nature:新发现!首次阐明大脑推理神经过程

人类具有快速适应不断变化的环境的认知能力。这种能力的核心是形成高级、抽象表示的能力&#xff0c;这些表示利用世界上的规律来支持泛化。然而&#xff0c;关于这些表征如何在神经元群中编码&#xff0c;它们如何通过学习出现以及它们与行为的关系&#xff0c;人们知之甚少。…

Kotlin 集合函数:map 和 first 的使用场景

Kotlin 提供了丰富的集合操作函数&#xff0c;使开发者可以更加简洁、高效地处理数据。其中&#xff0c;map 和 first 是两个常用的函数&#xff0c;分别用于转换集合和获取集合中的第一个元素。 1. map 的使用场景 场景 1&#xff1a;对象列表转换 在开发中&#xff0c;我们…

EIR管理中IMEI和IMSI信息的作用

在EIR&#xff08;设备身份注册&#xff09;管理中&#xff0c;IMEI&#xff08;国际移动设备身份码&#xff09;和IMSI&#xff08;国际移动用户识别码&#xff09;各自具有重要作用&#xff0c;以下是详细介绍&#xff1a; IMEI的作用 设备身份识别&#xff1a;IMEI是移动设…

MAUI开发第一个app的需求解析:登录+版本更新,用于喂给AI

vscode中MAUI框架已经搭好,用MAUI+c#webapi+orcl数据库开发一个app, 功能是两个界面一个登录界面,登录注册常用功能,另一个主窗体,功能先空着,显示“主要功能窗体”。 这是一个全新的功能,需要重零开始涉及所有数据表 登录后检查是否有新版本程序,自动更新功能。 1.用户…

KUKA机器人查看运行日志的方法

对于KUKA机器人的运行日志都是可以查看和导出的&#xff0c;方便查找问题。KUKA机器人的运行日志查看方法如下&#xff1a; 1、在主菜单下&#xff0c;选择【诊断】-【运行日志】-【显示】下打开&#xff1b; 2、显示出之前的机器人运行日志&#xff1b; 3、也可以通过【过滤器…

Kali Linux 2025.1a:主题焕新与树莓派支持的深度解析

一、年度主题更新与桌面环境升级 Kali Linux 2025.1a作为2025年的首个版本&#xff0c;延续了每年刷新主题的传统。本次更新包含全新的启动菜单、登录界面及桌面壁纸&#xff0c;涵盖Kali标准版和Kali Purple版本。用户可通过安装kali-community-wallpapers包获取社区贡献的额…

【UVM学习笔记】更加灵活的UVM—通信

系列文章目录 【UVM学习笔记】UVM基础—一文告诉你UVM的组成部分 【UVM学习笔记】UVM中的“类” 文章目录 系列文章目录前言一、TLM是什么&#xff1f;二、put操作2.1、建立PORT和EXPORT的连接2.2 IMP组件 三、get操作四、transport端口五、nonblocking端口六、analysis端口七…

uni-app项目上传至gitee方法详细教程

1. 准备工作 1.1 安装 Git 下载并安装 Git&#xff1a;前往 Git 官网&#xff0c;根据操作系统下载安装包。 配置用户名和邮箱&#xff08;需与 Gitee 账号一致&#xff09;&#xff1a; git config --global user.name "你的Gitee用户名" git config --global use…

走向多模态AI之路(三):多模态 AI 的挑战与未来

目录 前言一、多模态 AI 真的成熟了吗&#xff1f;二、多模态 AI 的主要挑战2.1 计算资源消耗&#xff1a;模型复杂度带来的成本问题2.2 数据标注困难&#xff1a;跨模态数据集的挑战2.3 对齐和融合的难点2.4 泛化能力与鲁棒性2.5 伦理与隐私问题 三、研究方向与未来发展3.1 轻…

STM32单片机入门学习——第12节: [5-2]对射式红外传感器计次旋转编码器计次

写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难&#xff0c;但我还是想去做&#xff01; 本文写于&#xff1a;2025.04.03 STM32开发板学习——第12节: [5-2]对射式红外传感器计次&旋转编码器计次 前言…

汇编学习之《jcc指令》

JCC&#xff08;Jump on Condition Code&#xff09;指的是条件跳转指令&#xff0c;c中的就是if-else, while, for 等分支循环条件判断的逻辑。它包括很多指令集&#xff0c;各自都不太一样&#xff0c;接下来我尽量将每一个指令的c 源码和汇编代码结合起来看&#xff0c;加深…

深度解析算法之滑动窗口

12滑动窗口—将 x 减到 0 的最小操作数 题目传送门 题目描述&#xff1a; 给你一个整数数组 nums 和一个整数 x 。每一次操作时&#xff0c;你应当移除数组 nums 最左边或最右边的元素&#xff0c;然后从 x 中减去该元素的值。请注意&#xff0c;需要 修改 数组以供接下来的操…

[MySQL初阶]MySQL表的操作

MySQL表的操作 1. 创建表2. 查看表结构3. 修改表&#xff08;修改表的属性而非表的数据&#xff09;4. 删除表 1. 创建表 语法&#xff1a; CREATE TABLE table_name (field1 datatype,field2 datatype,field3 datatype ) character set 字符集 collate 校验规则 engine 存储…

sqlalchemy详细介绍以及使用方法

SQLAlchemy是一个Python的ORM&#xff08;对象关系映射&#xff09;工具&#xff0c;它允许开发者使用Python代码来操作数据库而不必直接编写SQL语句。SQLAlchemy提供了一种抽象层&#xff0c;使开发者可以通过简单的Python对象来表示数据库表和记录&#xff0c;从而实现对数据…

图解AUTOSAR_SWS_LINDriver

AUTOSAR LIN驱动详解文档 基于AUTOSAR标准的本地互联网络(LIN)驱动程序技术规范解析 目录 1. 概述 1.1 AUTOSAR LIN驱动简介1.2 LIN协议基础2. LIN驱动架构 2.1 类图结构2.2 状态机设计3. LIN帧结构 3.1 基本帧组成3.2 PID结构4. LIN驱动配置 4.1 主要配置参数4.2 配置结构5. L…

《网络管理》实践环节03:snmp服务器上对网络设备和服务器进行初步监控

兰生幽谷&#xff0c;不为莫服而不芳&#xff1b; 君子行义&#xff0c;不为莫知而止休。 应用拓扑图 3.0准备工作 所有Linux服务器上&#xff08;服务器和Agent端&#xff09;安装下列工具 yum -y install net-snmp net-snmp-utils 保证所有的HCL网络设备和服务器相互间能…

2025年内外网文件交换系统排名分析

在时代&#xff0c;企业的日常运营离不开内外网文件的交换。然而&#xff0c;传统的文件传输方式难以满足企业对多方面的要求。以下是一些备受关注的内外网文件交换系统及其排名分析。 第一名&#xff1a;阳途内外网文件交换系统 阳途内外网文件交换系统是一款专为解决内外网…