leetcode刷题记录07(2023-04-30)【二叉树展开为链表 | 买卖股票的最佳时机 | 二叉树中的最大路径和(递归) | 最长连续序列(并查集)】

114. 二叉树展开为链表

给你二叉树的根结点 root ,请你将它展开为一个单链表:

展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。
展开后的单链表应该与二叉树 先序遍历 顺序相同。

示例 1

在这里插入图片描述

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

示例 2
输入:root = []
输出:[]

示例 3
输入:root = [0]
输出:[0]

提示:
树中结点数在范围 [ 0 , 2000 ] 内 树中结点数在范围 [0, 2000] 内 树中结点数在范围[0,2000]
− 100 < = N o d e . v a l < = 100 -100 <= Node.val <= 100 100<=Node.val<=100

进阶:你可以使用原地算法(O(1) 额外空间)展开这棵树吗?

现在刷leetcode经常一遍就可以通过,代码不需要调试,感觉还是很有成就感的,刷题确实有效果。

在这里插入图片描述

这道题目如果不要求使用原地算法(O(1) 额外空间),很简单,进行前序遍历,保存数组的指针到数组中,最后再进行一次树的重建,但是复杂度是O(n)。

或者采用一个栈的数据结构,保存一下右子树,不断地进行前序遍历,将当前节点添加到 pre->right 中,pre->left 中填写 nullptr

值得注意的是,需要对空子树进行处理,如果 root 节点为空,直接返回。

代码如下:

#include<stack>
using namespace std;// 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:void flatten(TreeNode* root) {if (root == nullptr) {return;}stack<TreeNode*> stk;if (root->right != nullptr) {stk.push(root->right);}// 前驱节点TreeNode* pre = root;// 当前节点TreeNode* cur = root->left;while (!stk.empty() || cur != nullptr) {if (cur == nullptr) {cur = stk.top();stk.pop();}// 将右节点入栈if (cur->right != nullptr) {stk.push(cur->right);}// pre->rightpre->right = cur;pre->left = nullptr;pre = pre->right;// 更新 curcur = cur->left;}}
};

虽然采用栈降低了空间复杂度,但是也并不能说是O(1)级别的,看了下题解,思路是:对于每个节点,每次将它的左节点变为空,然后就移动到它的右节点上去。主要是找到左子树中最后一个访问的节点,将右子树移到它上面,最后再将左子树整体移动到 root->right 上。

代码如下:

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

121. 买卖股票的最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

示例 1:
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例 2:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

提示:
1 < = p r i c e s . l e n g t h < = 1 0 5 1 <= prices.length <= 10^5 1<=prices.length<=105
0 < = p r i c e s [ i ] < = 1 0 4 0 <= prices[i] <= 10^4 0<=prices[i]<=104

还是一遍过!

在这里插入图片描述

主要思路就是从前向后进行遍历,保存最小值,然后用当前值-最小值,如果大于当前的最大利润,就更新最大利润。最后返回最大利润。

代码如下:

#include<vector>
using namespace std;class Solution {
public:int maxProfit(vector<int>& prices) {int minVal = 0x3f3f3f3f;int profit = 0;for (int i = 0; i < prices.size(); i++) {if (prices[i] < minVal)minVal = prices[i];profit = profit > (prices[i] - minVal) ? profit : (prices[i] - minVal);}return profit;}
};

124. 二叉树中的最大路径和

二叉树中的 路径 被定义为一条节点序列,序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。

路径和 是路径中各节点值的总和。

给你一个二叉树的根节点 root ,返回其 最大路径和 。

示例 1:

在这里插入图片描述

输入:root = [1,2,3]
输出:6
解释:最优路径是 2 -> 1 -> 3 ,路径和为 2 + 1 + 3 = 6

示例 2:

在这里插入图片描述

输入:root = [-10,9,20,null,null,15,7]
输出:42
解释:最优路径是 15 -> 20 -> 7 ,路径和为 15 + 20 + 7 = 42

提示:
树中节点数目范围是 [ 1 , 3 ∗ 1 0 4 ] 树中节点数目范围是 [1, 3 * 10^4] 树中节点数目范围是[1,3104]
− 1000 < = N o d e . v a l < = 1000 -1000 <= Node.val <= 1000 1000<=Node.val<=1000

很优美的代码,主要通过一个共享成员变量记录全局最优解,再 maxGain 内部有进行局部最优解的计算,并不断更新全局最优解。

同时,maxGain 的返回值,返回的是当前节点作为路径的一部分,要么要左子树,要么要右子树,不能两个都要(这样才能保证 同一个节点在一条路径序列中至多出现一次 )。

#include<algorithm>using namespace std;//  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 {int maxSum = -0x3f3f3f3f - 1;int maxGain(TreeNode* root) {if (root == nullptr) {return 0;}int leftGain = max(maxGain(root->left), 0);int rightGain = max(maxGain(root->right), 0);int curMax = root->val + leftGain + rightGain;maxSum = max(maxSum, curMax);return root->val + max(leftGain, rightGain);}public:int maxPathSum(TreeNode* root) {maxGain(root);return maxSum;}
};

128. 最长连续序列

给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

请你设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:
输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。

示例 2:
输入:nums = [0,3,7,2,5,8,4,6,0,1]
输出:9

提示:

0 < = n u m s . l e n g t h < = 1 0 5 0 <= nums.length <= 10^5 0<=nums.length<=105
− 1 0 9 < = n u m s [ i ] < = 1 0 9 -10^9 <= nums[i] <= 10^9 109<=nums[i]<=109

主要思路就是采用并查集来实现,首先要去重,得到一个哈希表,然后遍历这个哈希,如果存在连续的数,那么就需要进行合并,合并的时候要将大的数作为根,这样我们就将所有连续的数划分在一个集合里面了。

最后遍历一遍哈希表,判断当前元素是否为序列的第一个数。

  • 如果是第一个数,则找到它的祖先,根据祖先的值,就可以确定序列的长度。
  • 如果不是第一个数,不考虑。
#include<vector>
#include<unordered_map>
using namespace std;class Solution {vector<int> mergeAndFindSet;int find(int val) {while (mergeAndFindSet[val] != val){val = mergeAndFindSet[val];}return val;}void merge(int val1, int val2) {int i1 = find(val1);int i2 = find(val2);// 找到 i1 和 i2 后进行合并if (i1 == i2) return;mergeAndFindSet[i1] = i2;}
public:int longestConsecutive(vector<int>& nums) {unordered_map<int, int> mp;int n = nums.size();mergeAndFindSet = vector<int>(n, 0);for (int i = 0; i < n; i++) {mergeAndFindSet[i] = i;}for (int i = 0; i < n; i++) {mp[nums[i]] = i;}for (auto it = mp.begin(); it != mp.end(); it++) {int num = it->first;int i = it->second;if (mp.count(num + 1)) {        // 如果有连续的数就进行合并merge(i, mp[num + 1]);    // 合并需要将小的数合并到最大的根上}}int res = 0;for (auto it = mp.begin(); it != mp.end(); it++) {int num = it->first;int i = it->second;if (!mp.count(num - 1)) { // 如果当前这个数是最小的,寻找它的根int root = find(i);res = max(res, nums[root] - num + 1);}}return res;}
};

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

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

相关文章

SQL注入安全漏洞详解

1. SQL注入的原理&#xff1a; SQL注入的攻击行为是通过用户可控参数中注入了SQL语法&#xff0c;改变原有SQL结构&#xff0c;以下两种情况可以造成SQL注入&#xff1a; 1.使用字符串拼接的方式构造SQL语句 2.未对用户可控参数进行严格的过滤&#xff0c;便把参数内容拼接到…

AxGlyph安装教程

AxGlyph安装教程 AxGlyph是一款用于创建科学图表的强大工具&#xff0c;以下是AxGlyph的下载和安装步骤。 步骤一&#xff1a;下载AxGlyph 访问下载地址&#xff1a;点击下载 解压安装包 步骤二&#xff1a;运行安装程序 点击AxGlyph_Setup_Win7_8_10.exe进行安装 安装完成…

FHE简介

1. 引言 加密技术已经存在了数千年&#xff0c;用于相互发送秘密信息。例如&#xff0c;凯撒密码是最早的加密技术之一&#xff0c;可以追溯到公元前60年&#xff0c;其只由字母表中的字母交换组成。 随着互联网的出现&#xff0c;人们生成的私人数据量呈指数级增长&#xff…

【Maven】下载及配置

文章目录 1. 下载2. 解压3. 配置环境变量4. 验证 Maven 是一个跨平台的项目管理工具。作为 Apache 组织的一个颇为成功的开源项目&#xff0c;其主要服务于基于 Java 平台的项目创建&#xff0c;依赖管理和项目信息管理&#xff0c;是一个自动化构建工具&#xff0c;本文将介绍…

各种免费好用的api,含天气查询、IP查询、物流查询等

跨境国际快递物流查询&#xff1a;支持900物流商&#xff0c;提供实时查询和单号订阅API接口。稳定高效&#xff0c;为跨境电商平台、独立站、软件服务商提供优质服务。手机号码归属地&#xff1a;可根据手机号码查询其省市区、运营商区号行政区划代码等信息。 上亿条数据囊括最…

MySQL 的内连接、左连接、右连接有什么区别?

MySQL 的内连接、左连接、右连接有什么区别&#xff1f; 在 MySQL 中&#xff0c;内连接&#xff08;INNER JOIN&#xff09;、左连接&#xff08;LEFT JOIN 或 LEFT OUTER JOIN&#xff09;和右连接&#xff08;RIGHT JOIN 或 RIGHT OUTER JOIN&#xff09;是用于合并两个或多…

MySQL入门教程-触发器

9.触发器 什么是触发器 触发器(trigger)&#xff1a;监视某种情况&#xff0c;并进行某种操作&#xff0c;它的执行并不是程序调用&#xff0c;也不是手工启动&#xff0c;而是由事件来触发&#xff0c;例如&#xff1a;对一张表进行操作&#xff08;插入&#xff0c;更新&…

跨进程通信 macOS XPC 创建实例

一&#xff1a;简介 XPC 是 macOS 里苹果官方比较推荐和安全的的进程间通信机制。 集成流程简单&#xff0c;但是比较绕。 主要需要集成 XPC Server 这个模块&#xff0c;这个模块最终会被 apple 的根进程 launchd 管理和以独立进程的方法唤起和关闭&#xff0c; 我们主app 进…

JNPF开发平台--初体验

这一两年低代码的概念很流行&#xff0c;我也在网上了解体验了一番。 目前低代码主要分为两种&#xff0c;第一种是与云平台绑定的低代码&#xff0c;在云平台上开发&#xff0c;直接发布到云平台&#xff1b;第二种是低代码框架&#xff0c;低代码项目&#xff0c;这种比较流行…

C# 使用ZXing.Net生成二维码和条码

写在前面 条码生成是一个经常需要处理的功能&#xff0c;本文介绍一个条码处理类库&#xff0c;ZXing用Java实现的多种格式的一维二维条码图像处理库&#xff0c;而ZXing.Net是其.Net版本的实现。 在WinForm下使用该类库需要从NuGet安装两个组件&#xff1a; ZXing.Net ZXing…

当钉钉宜搭有销售单据或客户审批时,自动同步到畅捷通T+Cloud,赋能企业部门之间的业务流程自动化

1 场景描述 随着数字化转型&#xff0c;对于大规模的企业来说&#xff0c;都会选择低代码系统来搭建内部流程来提高公司的管理效率&#xff0c;例如使用钉钉宜搭作为企业的数据库&#xff0c;用来存储客户、供应商、单据等数据。也会使用畅捷通TCloud作为ERP系统解决管理财务、…

Vue - 表单输入绑定详解

Vue.js 表单输入绑定详解 在Web开发中&#xff0c;表单是用户与应用程序交互的重要方式之一。Vue.js 提供了强大的表单输入绑定机制&#xff0c;使得在处理用户输入时变得更加简洁和高效。本篇博客将深入探讨 Vue.js 中表单输入绑定的各种用法&#xff0c;包括文本输入、多行文…

type 和 interface的异同

// 使用type定义一个类型 type Person {name: string;age: number; }// 使用interface定义一个类型 interface Animal {name: string;age: number; }// 使用type定义一个函数签名 type Add (a: number, b: number) > number;// 使用interface定义一个函数签名 interface S…

【python】可变变量与不可变变量

不可变类型&#xff08;如整数和字符串&#xff09; 当您创建一个不可变对象&#xff08;如整数、字符串&#xff09;时&#xff0c;Python实际上是将这个值存储在内存中的某个位置&#xff0c;并将变量名指向这个值。例如&#xff1a; lens 10 count lens在这种情况下&…

Github 2023-12-30 开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2023-12-30统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量TypeScript项目4JavaScript项目2C项目1Python项目1Java项目1HTML项目1Dart项目1非开发语言项目1 令人惊叹的 …

2核2G3M服务器上传速度多少?以阿里云和腾讯云为例

2核2G3M服务器上传速度多少&#xff1f;上传是按10M带宽算&#xff0c;上传速度是1280KB/秒&#xff0c;即1.25M/秒&#xff1b;下载速度按3M带宽计算&#xff0c;下载速度是384KB/秒。本文是以阿里云为例的&#xff0c;阿里云服务器当公网带宽小于10M及10M以下时&#xff0c;上…

【51单片机系列】DS1302时钟模块扩展实验之与EEPROM结合使用只进行一次初始化工作

本文是关于时钟芯片DS1302的扩展实验。 文章目录 一、实验分析二、proteus仿真原理图三、软件设计及结果 本实验实现的目的&#xff1a;利用AT24C02掉电不丢失的功能&#xff0c;存储数据用来辨别DS1302时钟是否已经初始化&#xff0c;如果初始化就不执行DS1302初始化函数。 一…

【全网首发】洛谷P2678 [NOIP2015 提高组] 跳石头

Everyday English You don’t become what you want; you become whatyou believe. —Oprah Winfrey 你不是成为你想要的&#xff0c;你成为你所相信的。 洛谷P2678 [NOIP2015 提高组] 跳石头 题目描述 一年一度的“跳石头”比赛又要开始了&#xff01; 这项比赛将在一条笔…

arduino esp32连接阿里云物联网平台,上传和请求数据的示例代码

要在Arduino ESP32上连接到阿里云物联网平台&#xff0c;并上传和请求数据&#xff0c;您可以使用 PubSubClient 库和 WiFi.h 库来实现。以下是一个示例代码&#xff0c;演示了如何使用MQTT协议将数据上传到阿里云物联网平台&#xff0c;并从平台上请求数据。 #include <Wi…

ansible_角色的使用

本章主要介绍ansible中角色的使用 了解什么是角色独立地写一个角色使用角色系统自带角色地使用 1.了解角色 正常情况下&#xff0c;配置一个服务如 apache时&#xff0c;要做一系列的操作:安装、拷贝、启动服务等。如果要在不同的机器上重复配置此服务&#xff0c;需要重新执…