当前位置:网站首页>剑指offer专项突击版第17天
剑指offer专项突击版第17天
2022-08-02 09:14:00 【hys__handsome】
容易想到 O ( N 2 ) O(N^2) O(N2)的暴力遍历算法,本质上跟for双重循环暴力遍历很类似,就是实现代码需要的技巧较多也比较新颖。
class Solution {
public:
//保证root下每种路径中的每个结点都会选取,不会有路径中间存在没选取的结点
int dfs(TreeNode *root, int targetSum) {
if(!root) return 0;
int cnt = 0;
if(root->val == targetSum) cnt++;
cnt += dfs(root->left, targetSum - root->val);
cnt += dfs(root->right, targetSum - root->val);
return cnt;
}
int pathSum(TreeNode* root, int targetSum) {
if(!root) return 0;
//选取root点
int ans = dfs(root,targetSum);
//不选root点
ans += pathSum(root->left, targetSum);
ans += pathSum(root->right, targetSum);
return ans;
}
};
仔细思考会发现,这里面有很多重复计算的,可以使用前缀和优化成 O ( N ) O(N) O(N) 时间复杂度,其中前缀和值放在map的键上,值则为个数,这样就不用重新遍历一遍之前的前缀和,严谨的来讲因为用到map就导致算法复杂度为 O ( N ∗ l o g N ) O(N*logN) O(N∗logN)。
class Solution {
private:
unordered_map<long long, int> prefix;
// int ans = 0;
public:
int dfs(TreeNode *root, long long sum, int targetSum) {
if(!root) return 0;
sum += root->val;
int ans = 0;
if(prefix.count(sum-targetSum)) {
//sum - x = targetSum,其中x就是前面某个前缀和
ans += prefix[sum-targetSum];
}
prefix[sum]++;
ans += dfs(root->left, sum, targetSum);
ans += dfs(root->right, sum, targetSum);
prefix[sum]--; //回溯,不然会用到其他分支的结点之和
return ans;
}
int pathSum(TreeNode* root, int targetSum) {
prefix[0] = 1; //什么都没选,当某条从root开始的路径结点之和等于targetSum时会用到
return dfs(root, 0, targetSum);
}
};
使用到后序遍历+DP思想
- 后序遍历是先求左右子路径的最大值
- DP思想是当前栈帧会计算当前结点+左子路径+右子路径(这个不能回溯给父节点的,因为会使得路径不是线性的),不管你要回溯给父节点当前结点、当前+左子路径、当前+右子路径,最终得到的是全局最大的路径和。
class Solution {
private:
int res = INT_MIN;
public:
int maxPathSum(TreeNode* root) {
maxGain(root);
return res;
}
int maxGain(TreeNode *root) {
if(root == nullptr) return 0;
int left = maxGain(root->left);
int right = maxGain(root->right);
res = max(res, root->val); //考虑左右路径都为负值
res = max(res, root->val + left);
res = max(res, root->val + right);
res = max(res, root->val + left + right);
//回溯只能返回当结点值 或 当前+左 或 当前+右
return max(max(root->val,root->val+left), root->val+right);
}
};
代码简化版,左右为负值时不如不选,就为0
class Solution {
private:
int res = INT_MIN;
public:
int maxPathSum(TreeNode* root) {
maxGain(root);
return res;
}
int maxGain(TreeNode *root) {
if(root == nullptr) return 0;
//左右为负值时不如不选,就为0
int left = max(0,maxGain(root->left));
int right = max(0,maxGain(root->right));
res = max(res, root->val + left + right);
//回溯只能返回当结点值 或 当前+左 或 当前+右
return max(left,right) + root->val;
}
};
最容易想到的方法,先存下中序遍历序列,然后按照序列顺序指定每个结点的右结点,这样就等同于创建一个链表
class Solution {
public:
void inorder(vector<TreeNode*> &ls, TreeNode *root) {
if(!root) return;
inorder(ls,root->left);
ls.emplace_back(root);
inorder(ls,root->right);
}
TreeNode* increasingBST(TreeNode* root) {
vector<TreeNode*> ls;
inorder(ls,root);
auto head = new TreeNode(-1);
auto tmp = head;
for(auto cur: ls) {
cur->left = cur->right = nullptr;
tmp->right = cur;
tmp = cur;
}
return head->right;
}
};
来一个难一些的方法,一边遍历一边改变结点指针方向。抓住中序遍历算法->遍历顺序不变的特性。然后用一个移动指针跟着遍历顺序移动。(有个坑,移动指针不能放函数参数里,必须全局变量,因为递归回溯过程中,移动指针还是原来的并没有改变)
class Solution {
private:
TreeNode *cur = nullptr;
public:
void inorder(TreeNode *root) {
if(!root) return;
inorder(root->left);
root->left = nullptr;
cur->right = root;
cur = cur->right;
inorder(root->right);
}
TreeNode* increasingBST(TreeNode* root) {
auto head = new TreeNode(-1);
cur = head;
inorder(root);
return head->right;
}
};
边栏推荐
- node封装一个图片拼接插件
- Navicat连接MySQL时弹出:1045:Access denied for user ‘root’@’localhost’
- In a recent build figure SLAM, and locate the progress
- 动态规划每日一练(3)
- 单机部署flink,创建oracle19c rac的连接表时报错 ORA-12505 ,怎么回事?
- 【论文阅读】Distilling the Knowledge in a Neural Network
- openpyxl 单元格合并
- 2022牛客暑期多校训练营4(ADHKLMN)
- PyCharm使用教程(详细版 - 图文结合)
- What attributes and methods are available for page directives in JSP pages?
猜你喜欢

RetinaFace: Single-stage Dense Face Localisation in the Wild

你有了解过这些架构设计,架构知识体系吗?(架构书籍推荐)

Pycharm (1) the basic use of tutorial

AutoJs学习-AES加解密

net start mysql MySQL 服务正在启动 . MySQL 服务无法启动。 服务没有报告任何错误。

大厂外包,值得拥有吗?

spark:商品热门品类TOP10统计(案例)

AutoJs学习-实现科赫雪花

location对象,navigator对象,history对象学习

腾讯T8架构师,教你学中小研发团队架构实践PDF,高级架构师捷径
随机推荐
RPA助你玩转抖音,开启电商运营新引擎
State Management in Jetpack Compose
How to use postman
谈谈对Volatile的理解
AI目标分割能力,无需绿幕即可实现快速视频抠图
数据库mysql
干货|如何在海量文件系统中选择合适自己的文件系统
【Redis】Jedis
day_05_pickel 和 json
【论文阅读】Distilling the Knowledge in a Neural Network
spark:页面单跳转换率统计(案例)
大厂外包,值得拥有吗?
Jenkins--基础--6.2--Pipeline--语法--声明式
HCIA动态主机配置协议实验(dhcp)
Daily practice of dynamic programming (2)
nacos项目搭建
PyCharm使用教程(较详细,图+文)
堪称神级的阿里巴巴“高并发”教程《基础+实战+源码+面试+架构》
Golang ORM框架 — GORM
day——05 迭代器,生成器