【C++】 —— 笔试刷题day_28

【C++】 —— 笔试刷题day_28

一、游游的重组偶数

题目解析

在这里插入图片描述
这道题,有q组数据,每一次输入一个正整数x,让我们将这个数进行重排,变成一个偶数,然后返回(如果x本身就是一个偶数那可以直接返回x);

如果不存在合法解,就是x通过重排后,无法变成一个偶数,就输出-1

算法思路

这道题,总体来说还是比较简单的;

对于正整数x,我们可以把它当作一个字符串进行输入;(如果按照整数输入,我们还要将这个数x的每一位变换成对应数组)

我们知道,如果一个数是偶数,那最低位一定是一个偶数,这样我们只需判断字符串的最后一位即可知道这个数是否是偶数;如果这个数是偶数,那就直接输出即可;如果最后一位不是偶数,那就从第一位开始向后找,找到一位是偶数,然后把它交换到最后一位;然后输出即可;如果遍历完这个字符串,还没找到一位是偶数的,那就表示这个数x通过重拍无法变成偶数,输出-1即可。

题目解析

#include<iostream>usingnamespace std; string func(){ string str; cin >> str;int n = str.size();if((str[n -1]-'0')%2==0)return str;for(int i =0; i < n -1; i++){if((str[i]-'0')%2==0){swap(str[i], str[n -1]);return str;}}return"-1";}intmain(){int q; cin >> q;while(q--){ cout <<func()<< endl;}return0;}

二、体操队形

题目解析

在这里插入图片描述
dd作为体操队长,现在要对体操队的n名同学(1 ~ n)进行排队;对于第i号队员,会有一个诉求a[i],表示i要排在a[i]的前面;如果a[i] == i,那就表示当前i号队员没有任何诉求,排在哪里都行。

现在dd想知道一共有多少种排队方案。

算法思路

初看这道题,可以说毫无头绪,根本无从下手;

我们要对n个队员排序;一部分队员还要求排在某个队员的前面,对于这个要求,我们很容易就可以解决了:

我们从左到右依次排队即可,排第i个队员时,只需判断它的诉求a[i]有没有排过就OK了。

那对于第i个位置,我们怎们知道某一个队员,能否在这个位置呢?

这就非常简单了,我们只需要记录一下每一个队员是否已经排过队了即可;

我们只需遍历每一个队员,看这一个队员是否能够放到该位置即可;

而我们一个队员不能放到该位置,有两种情况:一是这个队员已经排过了,我们接着遍历下一个队员即可;另一种则是,当前队员的诉求a[i]已经排过了,也就是该队员的诉求[i]在该队员i的前面;那此时无论我们怎们排,那肯定是不满足条件的;那我们就无需向后进行排了。

看到这里,相信大致思路以及能够理清楚了,我们先来绘制一下这道题的一个决策树:

在这里插入图片描述

代码实现

#include<iostream>usingnamespace std;int arr[11];//每一个队员的诉求bool vis[11];//记录每一个队员是否被排过int ret =0;//最终结果int n;voidbfs(int pos){if(pos == n +1){//表示找到一种排序方案 ret++;return;}for(int i =1;i<=n;i++){if(vis[i]==true)//i队员已经被排过continue;if(vis[arr[i]]==true)//i队员的诉求已经排过,也就是arr[i] 在 i的前面了,无论怎么排都不满足条件return; vis[i]=true;//当前位置被排过bfs(pos +1);//排下一个位置 vis[i]=false;//修改,回溯}}intmain(){ cin>>n;for(int i =1;i<=n;i++){ cin>>arr[i];}bfs(1);//从第一个位置开始填 cout<<ret<<endl;return0;}

三、二叉树中的最大路径和

题目解析

在这里插入图片描述
这道题还是比较难理解的,我们来看:

题目给定一个二叉树,让我们求出最大路径和;

路径:我们可以从二叉树中的任意节点出发,通过父 -> 子或者子 -> 父,到达任意节点的序列。同一个节点在一个二叉树路径中最多只能出现一次,简单来说就是同一个节点只能经过一次;一个路径至少包含一个节点,而且不一定要包含跟节点。

就如示例中给的1 , 2 , 3,最优路径就是2 -> 1 -> 3或者3 -> 1 -> 2

算法思路

OK啊,初看这道题,如果题目读的似懂非懂的,那可以说一点思路没有(博主第一次看到这道题就是这样的)

仔细思考一下,这道题不就是一个递归/dfs问题吗;

这里分享一下博主做题时的思路:

对于题目描述,我们要找的路径,它可以是从一个节点先一直向上走,然后在某一个节点,开始再走向子节点;当然也可以是从一个节点一直向上走,不再向下走向子节点。

所以对于二叉树的每一个节点我们可以求一下,在这一个节点为转折点时的最大路径和;

我们要求某一个节点为转折点的最大路径和,那我们就要知道左子树单路径的最大路径和和右子树单路径的最大路径和;我们就只能通过递归的返回值来获得,所以我们返回值就表示从一个节点向下走到nullptr的单路径的最大路径和。

所以在遍历到某一个节点时,要做的就是:求以这个节点为转折点时的最大路径和;然后返回从这个节点向下走到nullptr的单路径的最大路径和。

如果左子树和右子树的最大单路径和是<0的,我们可以不向下走(因为我们要求的是最大路径和);

这样我们只需要考虑最大路径和的第一种情况,就是先向上走,但某一个节点再向下走;对于第二种情况,不就是我们返回值的情况吗。

但是上述中存在一个问题,也是博主在写这道题时没有注意到的一个问题:

这里博主直接判断的是左子树和右子树的最大单路径和都>0时,才计算左右子树最大单路径的和;博主没有考虑到如果左子树和右子树的最大单路径和一个<0,一个小于>0时的情况;

因为博主的疏忽,这也导致博主的思路有一个漏洞:如果考虑我们以某一个节点为转折点的情况,那最大路径和是第二章情况时,我们求出来的就是错误的答案;就比如10 , 5 , -9,正确结果是15而我们求出来的就是10

因为5 -> 10这一种情况在函数最后的返回值当中,而这里没有考虑这一个返回值。(但是这里,是可以通过这道题目的,可以是这道题没有这种情况的测试用例)。

无论如何,博主感觉自己的思路还是存在漏洞的,要在最后考虑一个递归函数的返回值。

OK啊,现在来看这道题的思路:

其实上述就是这道题的大致思路了,哈哈!

我们要求二叉树中的最大路径和,我们要采用递归,bfs;(递归肯定是后序遍历)

那遍历到一个节点时,我们要求什么?

在博主的思路中,求的是以这个节点为转折点的路径和的最大值;

但是如果左子树和右子树某个子树中的最大单路径和<0时,那此时的最大路径和就不是上述中的第一种情况了,而是第二种情况;那我们就漏掉了一直情况。

所以这里我们在遍历到一个节点时,要求的是在该子树中,经过该节点的路径的最大路径和。

那要求经过该节点的最大路径和,我们就要知道左子树和右子树的最大单路径的和

所以我们的返回值就表示该子树中的最大单路径的和,当然要经过当前节点。

OK我们知道了要求什么,和返回值是什么,现在来看如何去求:

经过该节点的最大路径和,那当左右子树最大单路径和可能是小于0的,而<0时,我们肯定不会向下走的,所以我们可以对左右子树的最大单路径和与0求一个最大值;

也就是说当左右子树的最大单路径和是<0时,我们求经过该节点的最大路径和时,左leftright子树最大单路径和是=0的;我们当前节点就表示一个路径。

**返回值:**因为我们这里的leftright都是>=0的,我们直接返回当前节点的值val + max(left,right)即可。

这样最后,我们就无需再对递归函数的返回值就行判断,直接返回结果即可。

代码实现

博主自己的思路:

classSolution{public:int ret =-1000*100000;intfunc(TreeNode* root){if(root ==nullptr)return0;int left =func(root->left);int right =func(root->right);//求if(left >=0&& right >=0) ret =max(ret, left + right + root->val);else ret =max(ret,root->val);returnmax(left,right)+ root->val;}intmaxPathSum(TreeNode* root){returnmax(ret,func(root));}};

优化后的思路代码:

classSolution{public:int ret =-1010;intbfs(TreeNode* root){if(root ==nullptr)return0;int left =max(bfs(root->left),0);int right =max(bfs(root->right),0); ret =max(ret, root->val + left + right);return root->val +max(left, right);}intmaxPathSum(TreeNode* root){// write code herebfs(root);return ret;}};

到这里,本篇文章内容就结束了,感谢各位支持

Read more

【C++】深入拆解二叉搜索树:从递归与非递归双视角,彻底掌握STL容器的基石

【C++】深入拆解二叉搜索树:从递归与非递归双视角,彻底掌握STL容器的基石

【C++】深入拆解二叉搜索树:从递归与非递归双视角,彻底掌握STL容器的基石 * 摘要 * 目录 * 一、概念 * 二、 性能分析 * 三、key结构非递归模拟实现 * 1. 二叉搜索树的插入 * 2. 二叉搜索树的查找 * 3. 二叉搜索树的删除 * 4. 二叉搜索树的中序遍历 * 四、key结构递归的模拟实现 * 1. 递归与非递归二叉搜索树核心操作的对比 * 2. 递归插入 * 3. 递归查找 * 4. 递归删除 * 总结 摘要 二叉搜索树(BST)是一种重要的数据结构,它通过"左子树所有节点值小于根节点,右子树所有节点值大于根节点"的特性实现高效的元素组织。本文详细解析了BST的核心概念、性能特点,并分别通过非递归和递归两种方式完整实现了插入、查找、删除等关键操作,深入探讨了指针引用在递归实现中的巧妙应用,以及两种实现方式在时间复杂度、空间复杂度和适用场景上的差异。 目录

By Ne0inhk
C++ 多线程同步之互斥锁(mutex)实战

C++ 多线程同步之互斥锁(mutex)实战

C++ 多线程同步之互斥锁(mutex)实战 💡 学习目标:掌握 C++ 标准库中互斥锁的基本用法,理解多线程同步的核心原理,能够解决多线程环境下的资源竞争问题。 💡 学习重点:std::mutex 与 std::lock_guard 的使用、死锁的产生原因及规避方法、实际场景中的同步案例实现。 48.1 多线程同步的必要性 在多线程编程中,当多个线程同时访问共享资源时,会出现资源竞争问题。 例如两个线程同时对同一个变量进行读写操作,会导致最终结果与预期不符。 这种问题被称为线程安全问题,而解决该问题的核心就是线程同步。 ⚠️ 注意事项:线程不同步会引发数据竞争,造成程序运行结果不可预测,甚至导致程序崩溃。 举个简单的反例,两个线程同时对全局变量 count 进行自增操作: #include<iostream>#include<thread>usingnamespace std;int count

By Ne0inhk
(最新原创毕设)Java上门帮厨管理系统/03.01白嫖源码+演示录像)|可做计算机毕设Java、Python、PHP、小程序APP、C#、爬虫大数据、单片机、文案

(最新原创毕设)Java上门帮厨管理系统/03.01白嫖源码+演示录像)|可做计算机毕设Java、Python、PHP、小程序APP、C#、爬虫大数据、单片机、文案

摘  要 随着现代生活节奏的加快和人们对便捷、高质量餐饮服务需求的增加,上门帮厨作为一种新兴的服务模式逐渐受到欢迎。然而,传统的上门帮厨管理方式依赖于电话预约和手工记录,不仅效率低下,而且难以满足用户对服务质量透明度和个性化的需求。为此,本文提出了一个基于Spring Boot框架的临沂上门帮厨管理系统。该系统旨在通过信息化手段优化厨师与用户之间的互动流程,提高服务效率,增强用户体验,并为管理者提供有效的运营支持。 基于Spring Boot的临沂上门帮厨管理系统集成了多种功能模块,以满足不同用户群体的需求。普通用户可以通过注册登录进入系统,浏览首页展示的轮播图、菜品资讯、菜品信息推荐等信息,并进行相关操作。系统提供了菜品资讯的查看、点赞、收藏和评论功能,以及菜品信息的详情查看、评分、预约等功能。用户还可以在线提交问题反馈,查看个人账户信息并进行修改。 厨师用户可以查看订单详情,进行订单审核和回复,提交佣金提现申请,并查看提现记录。这些功能模块的设计充分考虑了厨师的实际需求,旨在帮助他们更好地管理和提升自己的服务水平。 管理员负责整个系统的运维工作,包括新注册用户的审核、菜品信

By Ne0inhk
C++ 多态:面向对象的动态行为核心机制

C++ 多态:面向对象的动态行为核心机制

C++ 多态:面向对象的动态行为核心机制 💡 学习目标:掌握多态的概念与分类,理解虚函数的作用原理,能够熟练使用多态实现程序的动态行为扩展。 💡 学习重点:静态多态与动态多态的区别、虚函数的定义与使用、纯虚函数与抽象类、多态的实战应用场景。 一、多态的概念与分类 ✅ 结论:多态是 C++ 面向对象三大特性之一,指同一行为在不同对象上表现出不同的形态,核心是“一个接口,多种实现”。 多态主要分为两大类,二者的实现原理和触发时机截然不同: 1. 静态多态:编译阶段确定调用关系,也叫编译时多态,实现方式包括函数重载和运算符重载 2. 动态多态:运行阶段确定调用关系,也叫运行时多态,实现方式是虚函数 + 基类指针/引用 生活中的多态示例:同样是“动物叫”这个行为,猫的叫声是“喵喵喵”,狗的叫声是“汪汪汪”,不同动物对象表现出不同的行为形态。 二、静态多态:编译时确定的多态性 💡 静态多态的调用关系在编译阶段就已确定,编译器会根据参数列表的差异匹配对应的函数。

By Ne0inhk