【复习3-5天的内容】【我们一起60天准备考研算法面试(大全)-第七天 7/60】

news2024/11/16 19:28:14

专注 效率 记忆
预习 笔记 复习 做题

欢迎观看我的博客,如有问题交流,欢迎评论区留言,一定尽快回复!(大家可以去看我的专栏,是所有文章的目录)
 
文章字体风格:
红色文字表示:重难点★✔
蓝色文字表示:思路以及想法★✔
 
如果大家觉得有帮助的话,感谢大家帮忙
点赞!收藏!转发!

本博客带大家一起学习,我们不图快,只求稳扎稳打。
由于我高三是在家自学的,经验教训告诉我,学习一定要长期积累,并且复习,所以我推出此系列。
只求每天坚持40分钟,一周学5天,复习2天
也就是一周学10道题
60天后我们就可以学完81道题,相信60天后,我们一定可以有扎实的代码基础!我们每天就40分钟,和我一起坚持下去吧!
qq群:878080619

第七天【考研408-数据结构(笔试)】

  • 五、表达式求值
    • 1. 表达式求值
  • 六、树的遍历( 递归 )
    • 1. 二叉树的带权路径长度
    • 2. 重建二叉树
        • 构建二叉树的两种情况
  • 七、二叉搜索树与表达式树
    • 1. 二叉排序树(中序遍历是有序的)
    • 2. 表达式树
  • 八、Huffman树
    • 1. 合并果子
    • 2. 荷马史诗
        • 考点:( 构建深度最小的哈夫曼树 )利用pair
        • 考点:( k进制哈夫曼树需要补零节点 )

五、表达式求值

1. 表达式求值

在这里插入图片描述

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

#include <iostream>
#include <stack>
#include <string>
#include <unordered_map>
using namespace std;

stack<int> num;
stack<char> op;

//优先级表
unordered_map<char, int> h{ {'+', 1}, {'-', 1}, {'*',2}, {'/', 2} };


void eval()//求值
{
    int a = num.top();//第二个操作数
    num.pop();

    int b = num.top();//第一个操作数
    num.pop();

    char p = op.top();//运算符
    op.pop();

    int r = 0;//结果 

    //计算结果
    if (p == '+') r = b + a;
    if (p == '-') r = b - a;
    if (p == '*') r = b * a;
    if (p == '/') r = b / a;

    num.push(r);//结果入栈
}

int main()
{
    string s;//读入表达式
    cin >> s;

    for (int i = 0; i < s.size(); i++)
    {
        if (isdigit(s[i]))//数字入栈
        {
            int x = 0, j = i;//计算数字
            while (j < s.size() && isdigit(s[j]))
            {
                x = x * 10 + s[j] - '0';
                j++;
            }
            num.push(x);//数字入栈
            i = j - 1;
        }
        //左括号无优先级,直接入栈
        else if (s[i] == '(')//左括号入栈
        {
            op.push(s[i]);
        }
        //括号特殊,遇到左括号直接入栈,遇到右括号计算括号里面的
        else if (s[i] == ')')//右括号
        {
            while(op.top() != '(')//一直计算到左括号
                eval();
            op.pop();//左括号出栈
        }
        else
        {
            while (op.size() && h[op.top()] >= h[s[i]])//待入栈运算符优先级低,则先计算
                eval();
            op.push(s[i]);//操作符入栈
        }
    }
    while (op.size()) eval();//剩余的进行计算
    cout << num.top() << endl;//输出结果
    return 0;
}

六、树的遍历( 递归 )

1. 二叉树的带权路径长度

在这里插入图片描述

class Solution {
public:
    int sum(TreeNode* root, int level) {
        if(!root) return 0;
        if(!root->left && !root->right) {
            return root->val * level;
        }
        return sum(root->left, level + 1) + sum(root->right, level + 1);
    }

    int pathSum(TreeNode* root) {
        return sum(root, 0);
    }
};

2. 重建二叉树

构建二叉树的两种情况

构建二叉树的两种情况【根据前序遍历和中序遍历 构造树】【根据后序遍历和中序遍历 构造树】
在这里插入图片描述

/**
 * 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:

    unordered_map<int,int> pos;

    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int n = preorder.size();
        for (int i = 0; i < n; i ++ )
            pos[inorder[i]] = i;
        return dfs(preorder, inorder, 0, n - 1, 0, n - 1);
    }

    TreeNode* dfs(vector<int>&pre, vector<int>&in, int pl, int pr, int il, int ir)
    {
        if (pl > pr) return NULL;
        int k = pos[pre[pl]] - il;
        TreeNode* root = new TreeNode(pre[pl]);
        root->left = dfs(pre, in, pl + 1, pl + k, il, il + k - 1);
        root->right = dfs(pre, in, pl + k + 1, pr, il + k + 1, ir);
        return root;
    }
};

七、二叉搜索树与表达式树

1. 二叉排序树(中序遍历是有序的)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
解释一下删除操作的第三点:

首先我们要清楚:
二叉排序树的特点是
中序遍历(左根右)是有序的

所以如果删除的根节点有左右子树

那么我们为了保证有序

就要把 根节点左子树的最右边 赋值给根节点
因为根节点左子树的最右边是比根节点小中最大的点

只有这样才能保证删除根节点后

左子树比新的根节点都小
右子树比新的根节点都大

#include <bits/stdc++.h>

using namespace std;

const int INF = 2e9;

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

// 插入操作
void insert(TreeNode* &root, int x)
{
    /*
        1. 递归找到x的待插入的位置
        2. 如果x < 当前root就递归到左子树,反之,递归到右子树。
    */ 
    if (!root) root = new TreeNode(x);
    // 如果发现数值相同的话就判断一下;
    if (root->val == x) return;
    else if (x < root->val) insert(root->left, x);
    else insert(root->right, x);
}

void remove(TreeNode* &root, int x)
{
    /*
        1. 待删除的结点只有左子树。立即可推出,左子树上的结点都是小于待删除的结点的,我们只需要把待删除结点删了然后左子树接上待删除结点的父节点就可以了。
        2. 待删除的结点只有右子树。立即可推出,右子树上的结点都是大于待删除的结点的,我们只需要把待删除结点删了然后右子树接上待删除结点的父节点就可以了。
        3. 待删除的结点既有左子树又有右子树。这个比上两个情况麻烦一点,但也不麻烦,需要读者理解的是,怎么能删除结点后还不改变中序遍历的结果,并且操作代价最小,显而易见,我们根据待删除结点的左子树可以得到最右下角的最后结点满足$<x$并且最接近x的结点,把这个结点覆盖待删除的结点,然后把这个结点删除,就完成了我们的操作。
    */

    // 如果不存在直接return
    if (!root) return;
    if (x < root->val) remove(root->left, x);
    else if (x > root->val) remove(root->right, x);
    else
    {
        if (!root->left && !root->right) root = NULL;
        else if (!root->left) root = root->right;
        else if (!root->right) root = root->left;
        else
        {
            auto p = root->left;
            while (p->right) p = p->right;
            root->val = p->val;
            remove(root->left, p->val);
        }
    }
}

// 输出数值 x 的前驱(前驱定义为现有所有数中小于 x 的最大的数)。
int get_pre(TreeNode* root, int x)
{
    if (!root) return -INF;
    if (root->val >= x) return get_pre(root->left, x);
    else return max(root->val, get_pre(root->right, x));
}

// 输出数值 x 的后继(后继定义为现有所有数中大于 x 的最小的数)。
int get_suc(TreeNode* root, int x)
{
    if (!root) return INF;
    if (root->val <= x) return get_suc(root->right, x);
    else return min(root->val, get_suc(root->left, x));
}

int main()
{
    int n;
    cin >> n;
    while (n--)
    {
        int t, x;
        cin >> t >> x;
        if (t == 1) insert(root, x);
        else if (t == 2) remove(root, x);
        else if (t == 3) cout << get_pre(root, x) << endl;
        else cout << get_suc(root, x) << endl;
    }
    return 0;
}

2. 表达式树

本题就是中序遍历
只要不是叶子节点
就加左括号然后遍历左边
遍历完右边加右括号

在这里插入图片描述

class Solution {
public:
    string dfs(TreeNode* root) {
        if(!root) return "";
        if(!root->left && !root->right) {
            return root->val;
        }
        string ret = "";
        ret += '(';
        ret += dfs(root->left);
        ret += root->val;
        ret += dfs(root->right);
        ret += ')';
        return ret;
    }

    string expressionTree(TreeNode* root) {
        return dfs(root->left) + root->val + dfs(root->right);
    }
};

八、Huffman树

1. 合并果子

在这里插入图片描述
什么是哈夫曼树

本题就记住哈夫曼树的最简代码如下:

#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

int main()
{
    int n;
    scanf("%d", &n);

    priority_queue<int, vector<int>, greater<int>> heap;
    while (n -- )
    {
        int x;
        scanf("%d", &x);
        heap.push(x);
    }

    int res = 0;
    while (heap.size() > 1)
    {
        int a = heap.top(); heap.pop();
        int b = heap.top(); heap.pop();
        res += a + b;
        heap.push(a + b);
    }

    printf("%d\n", res);
    return 0;
}

2. 荷马史诗

考点:( 构建深度最小的哈夫曼树 )利用pair

可以忽略这个段,下面有
图中所说的合并的次数,本质其实是根节点的深度
所以优先队列的元素是pair<long long ,int>
一个记录权值 一个记录深度

考点:( k进制哈夫曼树需要补零节点 )

题解图中有解释
原题链接

在这里插入图片描述
在这里插入图片描述
图中所说的合并的次数,本质其实是根节点的深度

所以优先队列的元素是pair<long long ,int>
一个记录权值 一个记录深度

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>

#define x first
#define y second

using namespace std;

typedef long long LL;
typedef pair<LL, int> PLI;

int main()
{
    int n, k;
    scanf("%d%d", &n, &k);
    priority_queue<PLI, vector<PLI>, greater<PLI>> heap;
    while (n -- )
    {
        LL w;
        scanf("%lld", &w);
        heap.push({w, 0});
    }
    while ((heap.size() - 1) % (k - 1)) heap.push({0, 0});

    LL res = 0;
    while (heap.size() > 1)
    {
        LL s = 0;
        int depth = 0;
        for (int i = 0; i < k; i ++ )
        {
            auto t = heap.top();
            heap.pop();
            s += t.x, depth = max(depth, t.y);
        }
        heap.push({s, depth + 1});
        res += s;
    }

    printf("%lld\n%d\n", res, heap.top().y);
    return 0;
}

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

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

相关文章

Ubuntu Linux系统下创建Git项目并push到远程Github

首先在本地创建git仓库 jasminelhl:~/prj$ mkdir Github-test jasminelhl:~/prj$ cd Github-test jasminelhl:~/prj/Github-test$ git init 提示&#xff1a;使用 master 作为初始分支的名称。这个默认分支名称可能会更改。要在新仓库中 提示&#xff1a;配置使用初始分支名&a…

RabbitMQ的可视化管理页面简介

模块 描述 Overview 概览 Connections 查看连接情况 Channels 信道(通过)情况 Exchanges 交换机(路由)情况,默认四类七个 Queues 消息队列情况 Admin …

高并发架构实战:从需求分析到系统设计

很多软件工程师的职业规划是成为架构师&#xff0c;但是要成为架构师很多时候要求先有架构设计经验&#xff0c;而不做架构师又怎么会有架构设计经验呢&#xff1f;那么要如何获得架构设计经验呢&#xff1f; 一方面可以通过工作来学习&#xff0c;观察所在团队的架构师是如何…

网络安全工程师工作内容具体是什么?

在知乎看到一个帖子&#xff1a;网络安全工程师或者网络安全研究员的工作内容具体是什么&#xff1f;或者说他们的一天具体是怎么度过的&#xff0c;是否和程序员一样编码做项目&#xff1f; Neeao的回复&#xff1a; 只在甲方互联网公司呆过&#xff0c;简单说下甲方的情况。…

“千模千测”——针对大语言模型认知能力的高效测试方法

©PaperWeekly 原创 作者 | 庄严、宁雨亭 单位 | 中国科学技术大学BASE课题组 论文标题&#xff1a; Efficiently Measuring the Cognitive Ability of LLMs: An Adaptive Testing Perspective 作者&#xff1a; Yan Zhuang, Qi Liu, Yuting Ning, Weizhe Huang, Rui Lv, …

Docker 安装Nginx

查看Nginx镜像并拉取镜像&#xff1a; [rootlocalhost nginx]# docker search nginx NAME DESCRIPTION STARS OFFICIAL AUTOMATED nginx …

使用Mybatis添加记录错误

使用Mybatis添加记录错误&#xff1a;Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column ‘id’ at row 1 分析&#xff1a;添加记录的id值超出范围&#xff0c;查看JavaBean中的ID&#…

00-C++-ccache使用

ccache使用 前言ccache是什么ccache使用 前言 在编译大型C项目代码时编译时间比较长&#xff0c;那么可以使用ccache来加速代码的编译&#xff0c;一起来学习吧。 ccache是什么 ccache是一个编译器缓存。它通过缓存以前编译的结果并检测何时再次进行相同的编译来加快重新编译…

201天,太平洋保险核心系统迁至国产数据库OceanBase稳定运行

7月7日&#xff0c;2023全球数字经济大会上&#xff0c;国内首个全险种核心迁移至国产数据库的系统正式亮相。 因支撑未来海量并发、海量数据业务发展需求&#xff0c;太平洋保险&#xff08;集团&#xff09;股份有限公司&#xff08;以下称“太平洋保险”&#xff09;与Ocea…

使用OpenCV的viz模块创建和控制一个3D可视化窗口

#include <opencv2/viz.hpp> #include <iostream>using namespace cv; using namespace std;int main() {

神经网络解决预测问题(以共享单车预测为例)

背景:大约从2015年起,共享单车席卷了大部分城市。共享单车在给人们带来便利的同时,也存在一些问题:单车的分布很不均匀。比如在早高峰的时候,一些地铁口往往聚集着大量的单车,而到了晚高峰却很难找到一辆单车了。那么如何解决共享单车分布不均匀的问题呢?目前,共享单车…

DevOps系列文章 之 SnakeYAML解析与序列化YAML

1、简述 如何使用SnakeYAML库将YAML文档转换为Java对象&#xff0c;以及JAVA对象如何序列化为YAML文档。 在DevOps平台系统中是基础的能力支持&#xff0c;不管是spring boot 的配置还是K8S 资源清单yaml 2、项目设置 要在项目中使用SnakeYAML&#xff0c;需要添加Maven依赖…

基于go-zero的api服务刨析并对比与gin的区别

zero路由与gin的区别 官网go-zero go-zero是一个集成了各种工程实践的微服务框架&#xff0c;集多种功能于一体&#xff0c;如服务主要的API服务&#xff0c;RPC服务等。除了构建微服务工程外&#xff0c;zero也是一款性能优良的web框架&#xff0c;也可以构建单体web应用。 …

并行计算框架Polars、Dask的数据处理性能对比

在Pandas 2.0发布以后&#xff0c;我们发布过一些评测的文章&#xff0c;这次我们看看&#xff0c;除了Pandas以外&#xff0c;常用的两个都是为了大数据处理的并行数据框架的对比测试。 本文我们使用两个类似的脚本来执行提取、转换和加载(ETL)过程。 测试内容 这两个脚本主…

【Linux】-Linux部署Javaweb项目

作者&#xff1a;学Java的冬瓜 博客主页&#xff1a;☀冬瓜的主页&#x1f319; 专栏&#xff1a;【Linux】 分享: 屋檐如悬崖 风铃如沧海 我等燕归来 时间被安排 演一场意外 你悄然走开 故事在城外 浓雾散不开 看不清对白 你听不出来 风声不存在 是我在感慨 梦想来是谁在窗台 …

【服务器】Python一行命令搭建HTTP服务器并外网访问 - 内网穿透

文章目录 1.前言2.本地http服务器搭建2.1.Python的安装和设置2.2.Python服务器设置和测试 3.cpolar的安装和注册3.1 Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 转载自cpolar极点云文章&#xff1a;【Python】快速简单搭建HTTP服务器并公网访问「cpolar内网穿透」…

【专题速递】音频生成、TTS和AIGC在音乐上的运用

// AIGC的发展为音频带来了什么&#xff1f;AIGC如何赋能音乐创作&#xff1f;如何识别虚假音频&#xff1f;TTS可以在哪种场景下解决特定问题&#xff1f;7月29日LiveVideoStackCon2023上海站音频新体验专场&#xff0c;为您解答。 音频新体验 随着多媒体和通信网络技术的不…

开利网络受邀参与广州三会企业数字化转型专题研讨会

​7月6日&#xff0c;开利网络受邀出席由广州三会于广州市黄埔区组织的“广州三会第六届理事会第八次会长联席会议”&#xff0c;并进行了主题为“企业数字化转型如何推动企业价值再造&#xff1f;”的专题分享会&#xff0c;为各位参会来宾分享企业数字化转型常见误区及数字化…

【IC设计】ICC1 workshop lab guide 学习笔记——Lab 2 Design Planning Task5-9

文章目录 ICC1 workshop lab guide2.5 Create P/G Rings Around Macro Groups2.6 Power Network Synthesis2.7 Check the Timing2.8 Write Out the DEF Floorplan File2.9 Create 2nd Pass Design Ready for Placement ICC1 workshop lab guide 2.5 Create P/G Rings Around M…

uniapp 发送全文件 支持App端ios、android,微信小程序,H5

由于uniapp提供的API在app端只能上传图片和视频&#xff0c;不能上传其他文件&#xff0c;说以只能借助插件了。 ios端用的这个插件 获取到文件对象 免费的 这个是返回一个 filePath 可用直接用于 uni.uploadFile 上传的路径&#xff0c;后面自己又改的File对象 全文件上传选择…