秋招突击——6/14——复习{(树形DP)树的最长路径}——新作{非递归求二叉树的深度、重复区间合并}

文章目录

    • 引言
    • 复习
      • 树形DP——树的最长路径
    • 新作
      • 使用dfs非递归计算二叉树的深度
      • 多个区间合并删除问题
        • 实现思路
        • 实现代码
        • 参考思路
    • 总结

引言

  • 这两天可能有点波动,但是算法题还是尽量保证复习和新作一块弄,数量上可能有所差别。

复习

树形DP——树的最长路径

  • 这道题是没有完全听完,但是到现在这个阶段,最起码得数组实现邻接链表做完。

无向图的一维数组表示邻接表实现

  • 首先说明一下,这里要使用邻接链表实现,这里是使用一维数组实现的邻接链表。
  • 同时这里是双向链表,所以,要加两次边,具体是实现如下

在这里插入图片描述

下面开始具体的分析

  • 树是一个确定的拓扑结构,每一个节点之间是是存在对应的父子关系,所以列觉路径可以更换为枚举中间节点,具体分析见下图,这是参考别人的,分析的很有道理

  • 通过红色节点的有三条路径

    • 红色路径,是一红色节点为根节点的最长的路径
    • 蓝色路径,是以红色节点为跟节点的最长路径和次长路径的和
    • 橙色路径,是红色节点的父节点的相同情况,具体见上图。
  • 相当于这道题,就是在遍历的过程中,计算对应的最长路径和子路径,然后在计算两者的和。

图片参考来源
在这里插入图片描述

动态规划分析

  • 这道题是两个动态规划,分别是动态规划计算最长的路径,次长的路径,而且是一个很明显的动态规划题目,就是子状态影响最终的状态。
  • 所以状态转移函数,就是计算的最长路径和次长路径,这里的动态规划,就是两个路径,f1[i]表示以节点i为根节点的最长路径,f2[i]表示以i为根节点的次长路径。具体如下

在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

const int N = 10010;
int h[N],e[2*N],ne[2*N],w[2*N],idx;
int f1[N],f2[N],res; // f1保存最长的转移路径,f2保存次长的转移路径
int n;

void add(int a,int b,int c){
    e[idx] = b;
    w[idx] = c;
    ne[idx] = h[a];
    h[a] = idx ++;
}

void dfs(int r,int father){
    // 这里r是对应的根节点,father是对应的父节点
    f1[r] = 0,f2[r] = 0;
    for (int i = h[r]; ~i; i = ne[i]) {
        int j = e[i];  // 确定子节点的编号
        if (j == father)    continue;
        dfs(j,r);
        if(f1[j] + w[i] >= f1[r]) f2[r] = f1[r],f1[r] = f1[j] + w[i];
        else if(f1[j] + w[i] > f2[r]) f2[r] = f1[j] + w[i];
    }
    res = max(res,f1[r] + f2[r]);
}

int main(){
    cin>>n;
    // 构建无向图
    memset(h,-1,sizeof(h));
    for (int i = 0; i < n -1; ++i) {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c),add(b,a,c);
    }

    // 遍历对应的无向图
    for (int i = h[1]; ~i; i = ne[i]) {
        cout<<1<<"  "<<e [i]<<endl;
    }

    cout<<res;
    return 0;
}
  • 这道题拖了那么久,乍一看,其实还是蛮简单的,思路只要清楚了,后续还是很好实现的,然后那个使用一维数组实现的邻接链表的,之前是没有做过,现在知道怎么用了,还是蛮简单的。

新作

使用dfs非递归计算二叉树的深度

  • dfs非递归二叉树高度,一开始写了个经典队列的bfs,意识到不对后开始改,最后没改完,就说了个暴力找到每个叶子的高度的思路。

  • 这个忘记的有点多,如果单纯使用栈来实现的话,就需要每一次入栈当前节点的子节点还有对应的深度,然后出栈,如果是叶子节点,就比较一下长度,如果不是,就继续做出栈和入栈的操作。

  • 这里实现的基本上和我写的比较类似

#include <iostream>
#include <stack>

using namespace std;

struct TreeNode{
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x):val(x),left(NULL),right(NULL){};
};

// 生成样例
TreeNode* createSampleTree1() {
    TreeNode* root = new TreeNode(1);
    root->left = new TreeNode(2);
    root->right = new TreeNode(3);
    root->left->left = new TreeNode(4);
    root->left->right = new TreeNode(5);
    root->right->right = new TreeNode(6);
    root->left->left->left = new TreeNode(7);
    return root;
}

int treeHeight(TreeNode* root){
    // 使用非递归的方式计算的树深度
    stack<pair<TreeNode *,int>> s;

    // 根节点入栈并重置深度
    s.push({root,1});
    int r = 0;
    // 出栈并遍历每一个节点的子节点
    while(!s.empty()){
        TreeNode* t = s.top().first;
        int l = s.top().second;
        s.pop();

        // 判定左子节点是否为空
        if (t->left)    s.push({t->left,l + 1});
        if (t->right)    s.push({t->right,l + 1});

        // 比较深度
        r = max(r,l);
    }
    return r;
}

int main(){
    TreeNode* root = createSampleTree1();
    cout<<treeHeight(root);
}
  • 参考方法
    • 这里指的学习的是一个auto的使用,通过下述方式可以直接进行遍历使用。
auto [node, depth] = stack.top();
#include <iostream>
#include <stack>
#include <algorithm> // for max

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

int treeHeight(TreeNode* root) {
    if (root == nullptr) return 0;

    std::stack<std::pair<TreeNode*, int>> stack;
    stack.push({root, 1});
    int maxHeight = 0;

    while (!stack.empty()) {
        auto [node, depth] = stack.top();
        stack.pop();
        if (node != nullptr) {
            maxHeight = std::max(maxHeight, depth);
            if (node->left != nullptr) stack.push({node->left, depth + 1});
            if (node->right != nullptr) stack.push({node->right, depth + 1});
        }
    }

    return maxHeight;
}

int main() {
    // 示例二叉树
    TreeNode* root = new TreeNode(1);
    root->left = new TreeNode(2);
    root->right = new TreeNode(3);
    root->left->left = new TreeNode(4);
    root->left->right = new TreeNode(5);

    std::cout << "树的高度是: " << treeHeight(root) << std::endl;

    // 清理内存
    delete root->left->left;
    delete root->left->right;
    delete root->left;
    delete root->right;
    delete root;

    return 0;
}

多个区间合并删除问题

  • 这个也是在网上搜索的,部分拼多多主管面可能问到的题目,所以这里做一下,具体题目描述如下
给定一个n×2的二维数组,数组的每一行代表一个区间,
如果一个区间被另一个区间包含就删掉该区间,返回剩
下的所有区间。
* 比如: [1 2][1 ,3]包含。
实现思路
  • 这里是使用自定义排序实现的,如果包含关系,就将之按照包含的关系进行排序,然后在进行从前往后逐步进行遍历,对于相同的数组直接去除。最后剩下的就是对应的元素。
  • 自定义排序实现贪婪算法!
  • 这个方法确实是有问题的,有一部分样例是没有考虑到,不过背一下这个模版的。
实现代码
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

using Interval = pair<int,int>;

vector<Interval> removeContainedIntervals(vector<Interval>& intervals){

    // 可以对区间进行排序,按照包含关系进行排序
    vector<Interval> res;
    sort(intervals.begin(),intervals.end(),[](auto a,auto b){
        if(a.first <= b.first && a.second >= b.second)    return 1;
        else return 0;
    });
    for (int i = 0;i < intervals.size();i ++) {
        Interval t = intervals[i];
        res.push_back(t);
        while((i + 1 < intervals.size())
            && t.first <= intervals[i+1].first
            && t.second >= intervals[i+1].second)
            i ++;

    }
    return res;
}

int main() {
    vector<vector<Interval>> samples = {
            {{1, 4}, {2, 3}, {1, 3}, {4, 6}, {5, 7}},
//            {{1, 5}, {2, 4}, {6, 8}, {7, 9}, {5, 10}},
//            {{1, 2}, {3, 4}, {2, 3}, {1, 5}, {6, 7}},
//            {{1, 2}, {2, 3}, {3, 4}, {4, 5}},
//            {{1, 3}, {2, 6}, {8, 10}, {15, 18}}
    };

    for (size_t i = 0; i < samples.size(); ++i) {
        vector<Interval> result = removeContainedIntervals(samples[i]);
        cout << "样例 " << i + 1 << " 剩余的区间为:" << endl;
        for (const auto& interval : result) {
            cout << "[" << interval.first << ", " << interval.second << "] ";
        }
        cout << endl;
    }

    return 0;
}
参考思路
  • 这里是一个贪心算法解决区间问题的模板,需要好好练习一下,和我的方法差不多,只不过他是针对单边进行排序的
  • 这里是使用标准区间进行比较的,会更加灵活方便一点,比我的方法要好很多。
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

// 定义一个区间类型
using Interval = pair<int, int>;

// 比较函数,用于排序区间
bool compareIntervals(const Interval &a, const Interval &b) {
    if (a.first == b.first) {
        return a.second < b.second;
    }
    return a.first < b.first;
}

vector<Interval> removeContainedIntervals(vector<Interval>& intervals) {
    // 如果区间列表为空,直接返回空列表
    if (intervals.empty()) {
        return {};
    }

    // 按照起始点排序,起始点相同则按照终止点排序
    sort(intervals.begin(), intervals.end(), compareIntervals);

    vector<Interval> result;
    Interval last = intervals[0]; // 初始化第一个区间作为比较基准

    for (size_t i = 1; i < intervals.size(); ++i) {
        // 如果当前区间不被上一个区间包含
        if (intervals[i].first > last.first && intervals[i].second > last.second) {
            result.push_back(last); // 保留上一个区间
            last = intervals[i];    // 更新比较基准
        } else {
            // 如果当前区间的终止点更长,更新比较基准
            if (intervals[i].second > last.second) {
                last = intervals[i];
            }
        }
    }

    // 最后一个区间也需要保留
    result.push_back(last);

    return result;
}

int main() {
    vector<vector<Interval>> samples = {
        {{1, 4}, {2, 3}, {1, 3}, {4, 6}, {5, 7}},
        {{1, 5}, {2, 4}, {6, 8}, {7, 9}, {5, 10}},
        {{1, 2}, {3, 4}, {2, 3}, {1, 5}, {6, 7}},
        {{1, 2}, {2, 3}, {3, 4}, {4, 5}},
        {{1, 3}, {2, 6}, {8, 10}, {15, 18}}
    };

    for (size_t i = 0; i < samples.size(); ++i) {
        vector<Interval> result = removeContainedIntervals(samples[i]);
        cout << "样例 " << i + 1 << " 剩余的区间为:" << endl;
        for (const auto& interval : result) {
            cout << "[" << interval.first << ", " << interval.second << "] ";
        }
        cout << endl;
    }

    return 0;
}

总结

  • 复习的那个最长路径,还是蛮简单的,今天终于看懂了,继续加油吧。明天可以快速写一下。
  • 今天算是做了两道新的题目,dfs获取树的深度那道题,是自己做出来的,然后区间合并的那道题,是参考别人的,不过看了题解,加油吧!明天把题目再过一遍!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

弹幕逆向signature、a_bogus

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 本文章未经许可禁止转载&a…

qmt量化交易策略小白学习笔记第32期【qmt编程之获取行业概念数据--如何获取迅投行业成分股数据】

qmt编程之获取迅投行业成分股数据 qmt更加详细的教程方法&#xff0c;会持续慢慢梳理。 也可找寻博主的历史文章&#xff0c;搜索关键词查看解决方案 &#xff01; 感谢关注&#xff0c;咨询免费开通量化回测与获取实盘权限&#xff0c;欢迎和博主联系&#xff01; 获取迅投…

LeetCode | 387.字符串中的第一个唯一字符

这道题可以用字典解决&#xff0c;只需要2次遍历字符串&#xff0c;第一次遍历字符串&#xff0c;记录每个字符出现的次数&#xff0c;第二次返回第一个出现次数为1的字符的下标&#xff0c;若找不到则返回-1 class Solution(object):def firstUniqChar(self, s):""…

[大模型]Qwen2-7B-Instruct 接入 LangChain 搭建知识库助手

环境准备 在 autodl 平台中租赁一个 3090 等 24G 显存的显卡机器&#xff0c;如下图所示镜像选择 PyTorch–>2.1.0–>3.10(ubuntu20.04)–>12.1 接下来打开刚刚租用服务器的 JupyterLab&#xff0c;并且打开其中的终端开始环境配置、模型下载和运行 demo。 pip 换源…

2024 年最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)

OpenAi 环境安装 首先确保您的计算机上已经安装了 Python。您可以从 Python 官方网站下载并安装最新版本 Python。安装时&#xff0c;请确保勾选 “Add Python to PATH” &#xff08;添加环境变量&#xff09;选项&#xff0c;以便在 cmd 命令行中直接使用 Python。 安装 Op…

window上搭建open DHCP server踩坑记录

参考类似的安装说明 window10上搭建open DHCP server_opendhcpserver-CSDN博客 到安装目录里面 OpenDHCPServer.ini 这个是配置文件。 http://127.0.0.1:6789/ 是访问地址&#xff0c;这个地址只是显示结果&#xff0c;不能配置。 需要注意的是&#xff1a;必须要有一个静…

DockerHub无法访问,国内镜像拉取迂回解决方案

无法访问后&#xff0c;主要存在以下几个问题&#xff1a; 无法进行镜像的搜索无法查看镜像相关的使用说明无法直接拉取镜像 对于第二点&#xff0c;目前没啥解决思路&#xff0c;主要针对第一点和第三点。 解决无法搜索镜像 目前仅可以解决部分问题&#xff0c;在知道镜像名…

读AI新生:破解人机共存密码笔记01以史为鉴

1. 科学突破是很难预测的 1.1. 20世纪初&#xff0c;也许没有哪位核物理学家比质子的发现者、“分裂原子的人”欧内斯特卢瑟福&#xff3b;Ernest Rutherford&#xff3d;更为杰出 1.1.1. 卢瑟福早就意识到原子核储存了巨大的能量&#xff0c;然而&#xff0c;主流观点认为开…

Redis和Docker

Redis 和 Docker 是两种不同的技术&#xff0c;它们各自解决不同的问题&#xff0c;但有时会一起使用以提供更高效和灵活的解决方案。 Redis 是一个开源的内存数据结构存储系统&#xff0c;可以用作数据库、缓存和消息代理。它设计为解决MySQL等关系型数据库在处理大量读写访问…

针对k8s集群已经加入集群的服务器进行驱逐

例如k8s 已经有很多服务器&#xff0c;现在由于服务器资源过剩&#xff0c;需要剥离一些服务器出来 查找节点名称&#xff1a; kubectl get nodes设置为不可调度&#xff1a; kubectl cordon k8s-node13恢复可调度 kubectl uncordon k8s-node13在驱逐之前先把需要剥离驱逐的节…

[Java基本语法] 数组及其应用

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏:&#x1f355; Collection与数据结构 (92平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm1001.2014.3001.5482 &#x1f9c0;线程与…

AI绘画入门教程(非常详细)从零基础入门到精通Midjourney提示词,咒语

Microorganisms infiltrating through brain-machine interfaces --v 6.0 Microorganisms infiltrating through brain-machine interfaces ,redpupil --v 6.0 Microorganisms infiltrating through brain-machine interfaces,billion girls dream --v 6.0 --niji 6 “动漫风”…

【Redis】String的常用命令及图解String使用场景

本文将详细介绍 Redis String 类型的常见命令及其使用场景&#xff0c;包括缓存、计数器、共享会话、手机验证码、分布式锁等场景&#xff0c;并且配图和伪代码进一步方便理解和使用。 命令执行效果时间复杂度set key value [key value…]设置key的值是valueO(k),k是键个数get…

论文中引用网页链接的简单操作

一、参考资料 中文论文或者申请书中网页新闻引用格式 自制网页&#xff1a;在论文中快速引用网页链接 二、相关介绍 1. 常用文献类型用单字母标识 学术论文参考文献中文献类型字母标识 常用文献类型用单字母标识&#xff0c;具体如下&#xff1a; &#xff08;1&#xf…

react 0至1 案例

/*** 导航 Tab 的渲染和操作** 1. 渲染导航 Tab 和高亮* 2. 评论列表排序* 最热 > 喜欢数量降序* 最新 > 创建时间降序* 1.点击记录当前type* 2.通过记录type和当前list中的type 匹配*/ import ./App.scss import avatar from ./images/bozai.png import {useState} …

【YOLOv8改进[注意力]】在YOLOv8中添加GAM注意力 + 含全部代码和详细修改方式 + 手撕结构图

本文将进行在YOLOv8中添加GAM注意力的实践,助力YOLOv8目标检测效果的实践,文中含全部代码、详细修改方式以及手撕结构图。助您轻松理解改进的方法,实现有效涨点。 改进前和改进后的参数对比: 目录 一 GAM 二 在YOLOv8中添加GAM注意力 1 整体修改 2 配置文件

24年河北自考报名流程详细教程汇总

2024年河北自考本科报名马上就要开始了&#xff0c;想要参加考试报名的同学&#xff0c;提前看一下&#xff0c;了解一下报名流程&#xff0c;准备一些报名材料。 报名时间&#xff1a;2024年1月5日—10日8:00—22:00 考试时间&#xff1a;2024年4月13日—14日 报名照要求&…

UV胶带和UV胶水有什么区别?

UV胶带和UV胶水有什么区别&#xff1f; UV胶带和UV胶水在性质、用途、固化方式等方面存在明显的区别&#xff0c;以下是对两者区别的详细阐述&#xff1a; 性质&#xff1a; UV胶带&#xff1a;一种特殊的胶带&#xff0c;主要通过紫外线辐射进行固化&#xff0c;具有高强度粘…

后端高频面试题分享-用Java判断一个列表是否是另一个列表的顺序子集

问题描述 编写一个函数&#xff0c;该函数接受两个列表作为参数&#xff0c;判断第一个列表是否是第二个列表的顺序子集&#xff0c;返回True或False。 要求 判断一个列表是否是另一个列表的顺序子集&#xff0c;即第一个列表的所有元素在第二个列表需要顺序出现。列表中的元…

Linux iptables详解

前言&#xff1a;事情是这样的。最近部门在进行故障演练&#xff0c;攻方同学利用iptables制造了一个故障。演练最终肯定是取得了理想的效果&#xff0c;即业务同学在规定时间内定位了问题并恢复了业务(ps&#xff1a;你懂得)。 对我个人来讲一直知道iptables的存在&#xff0…