笔试编程算法题笔记(三 C++代码)

1.kotori和n皇后

 题意简单来说就是,在一个无穷大的棋盘上,不断插入k个皇后,皇后们如果在 同一行,同一列,在一个45°主对角线 在一个135°副对角线上,就可以互相攻击。

我们需要判断在第i个皇后插入后,是否存在互相攻击的情况。

解法:哈希表。

我们只需要将皇后的攻击范围存入哈希表(unordered_set)中,每次插入时判断这个皇后是否在这个攻击范围内即可。

因此我们需要创建四个哈希表。对应的行 列,两个对角线。

行和列很好理解,关于对角线

比如主对角线,如果y - x相等,说明在同一个主对角线上。同理,如果y + x相等,说明在同一个副对角线上。

最后,我们只需要记录下第一次出现皇后相互攻击的时机即可。

代码:

#include <iostream>
#include <unordered_set>using namespace std;int main()
{int k,t;cin >> k;int ret = 0x3f3f3f3f;unordered_set <int> row;unordered_set <int> low;unordered_set <int> dig1;// 主对角线unordered_set <int> dig2;// 副对角线int a,b;for(int i = 0; i < k; ++i){cin >> a >> b;if(row.count(a) || low.count(b) || dig1.count(b - a) || dig2.count(b + a)){if(ret == 0x3f3f3f3f){ret = i + 1;}}else {row.insert(a);low.insert(b);dig1.insert(b - a);dig2.insert(b + a);}}cin >> t;int tmp;for(int i = 0; i < t; ++i){cin >> tmp;if(tmp >= ret) cout << "Yes" << endl;else cout << "No" << endl;}return 0;
}

 2.取金币

 这是一道比较难的区间dp问题。

题意简单,图中很容易理解。

状态表示:

dp[i][j]表示区间[i,j]的金币全部拿走,能获得的最大积分是多少。

状态转移方程:

假设我们取了[i,j]区间的第k堆金币,那么此时区间[i,j]能获得的最大积分也就是dp[i][j] = 

dp[i][k - 1] + dp[k + 1][j] + arr[k] * arr[i - 1] * arr[j + 1]。( i <= k <= j )

记得每次要取最大值。

然后我们再来考虑一下边界情况

首先是对于源数组的,我们可以给源数组的左右两边都新增一个元素1,这样可以在不影响计算的情况下防止数组越界。

然后对于dp表,我们可以多开两行和多开两列, 因为源数组我们新增了两个元素1,所以多开两行和两列可以避免填表时数组越界,dp表都初始化为0不影响计算结果。

并且我们的填表总是在对角线及以上填表的。因为 i >= j。

再来看填表顺序,跟以往不同,我们要对照着状态转移方程来看

dp[i][k - 1] + dp[k + 1][j] + arr[k] * arr[i - 1] * arr[j + 1]。( i <= k <= j )

我们发现填表需要用到j + 1,要用到i - 1,所以填表顺序为从下往上,从左往右填。 

最后返回dp[1,n]即可。

代码:

class Solution {
public:int arr[110];int dp[110][110];int getCoins(vector<int>& coins) {int n = coins.size();arr[0] = arr[n + 1] = 1;for(int i = 1; i <= n; ++i) arr[i] = coins[i - 1]; // 新增两个元素for(int i = n; i >= 1; --i){for(int j = i; j <= n; j++){for(int k = i; k <= j; ++k)dp[i][j] = max(dp[i][j],dp[i][k - 1] + dp[k + 1][j] + arr[k] * arr[i - 1] * arr[j + 1]);}}return dp[1][n];}
};

3.四个选项

 题意简单来说就是有四个选项,给出四个选项的数量(保证四个选项加起来是12个),要将这些选项填到12个空里面,同时存在m个额外条件,每个条件使得第x个选项要等于第y个选项。

解法:递归 dfs

剪枝有两点:

1.如果当前该选项已经没有数量了,应该剪枝。

2.如果填入该选项发现不满足额外条件,应该剪枝。

细节:

1.可以用cnt[5]数组来存选项的数量,并用下标1 2 3 4 来映射选项的A B C D。

2.用哈希的思想来存额外条件,可以用一个二维的bool类型矩阵来存。

3.可以用一个变长数组来存选项填入的顺序,并事先加入一个占位符,方便对应下标映射关系。

代码:

#include <iostream>
#include <vector>using namespace std;int cnt[5];
int m,x,y;
bool same[13][13]; // 记录x,y相等的情况
int ret;
vector<int>path; // 存放路径bool isSame(int pos,int cur)
{for(int i = 1; i < pos; ++i){if(same[i][pos] && path[i] != cur) return false;}return true;
}void dfs(int pos)
{if(pos > 12){ret++;return;}for(int i = 1; i <= 4; ++i){if(cnt[i] == 0) continue; // 剪枝1 该选项数量已为0if(!isSame(pos,i)) continue; // 剪枝2 选项不相同cnt[i]--;path.push_back(i);dfs(pos + 1);cnt[i]++;path.pop_back();}
}int main()
{for(int i = 1; i <= 4; ++i) cin >> cnt[i];cin >> m;while(m--){cin >> x >> y;same[x][y] = same[y][x] = true;}path.push_back(0); // 先增一个占位符dfs(1);cout << ret << endl;return 0;
}

4.接雨水

 本题解法很多,这里采用动态规划(预处理)的解法。

思想:先求出每一根柱子上能接多少雨水,然后把所有柱子能接的雨水累加即可。

那么怎么计算第i根柱子能接多少雨水呢?我们发现,第i根柱子能接的雨水根取决与该柱子左边柱子的最大值和右边柱子的最大值,取二者的较小值就是该柱子能接的雨水量。

所有我们可以用两个数组,left[i],right[i]来记录第i根柱子左边柱子的最大值,和右边柱子的最大值。

也就是前缀最大值。

另外有一个细节:

比如left[i],这个数组表示的是区间[0,i]的最大值,要把i也带进去,因为我们计算每一个柱子的公式是 ret += min(left[i],right[i]) - height[i];  如果没有把i算进去的话,恰好i柱子是最高的,那么结果就会产生负值,是不合理的,最少的雨水量是0。所以我们把i也算进去,才是合理的。

代码:

class Solution {
public:int trap(vector<int>& height) {int n = height.size();vector<int> left(n);vector<int> right(n);left[0] = height[0];right[n - 1] = height[n - 1];for(int i = 1; i < n; ++i)left[i] = max(left[i - 1],height[i]);for(int i = n - 2; i >= 0; --i)right[i] = max(right[i + 1],height[i]);int ret = 0;for(int i = 0; i < n; ++i){ret += min(left[i],right[i]) - height[i];}return ret;}
};

5.栈和排序

 

解法:栈+贪心

 贪心思想:优先让当前最大的值出栈。

先创建一个栈

1.依次进栈。

2. 先更新目标值

3.如果当前的栈顶元素大于目标值,说明它是当前能输出的最大值。

另外可以定义一个哈希表,来存元素是否入栈。

class Solution {
public:vector<int> solve(vector<int>& a) {int n = a.size();stack<int> s;int aim = n; // 目标值vector<int> ret;vector<bool> hash(n + 1); for(auto x : a){s.push(x);hash[x] = true;while(hash[aim]) // 先更新目标值{aim--;}while(s.size() && s.top() >= aim){ret.push_back(s.top());s.pop();}}return ret;}
};

6.加减

 

综合性很强的一道题。

题意简单来说就是给了一个数组,还有最多k次操作机会,每次操作可以使数组的某个元素+1或者-1, 在经过最多k次操作后,使得数组中出现最多相同的数的次数,求出这个元素出现的次数。

思路: 

1.贪心思想:我们要尽可能的选择挨得近的数,这样把它们变成相同的数所花费的次数就会少。

那么我们可以先将数组进行排序,这样就可以让数组的元素尽可能挨得近。

2.之后,我们就可以枚举数组中所有的区间,找出使区间内所有数变成相同的数所花费的代价cost <= k,在这些区间中的最大区间。

如果直接暴力枚举,时间复杂度O(N^2),超时。

在枚举过程中,我们可以发现其left和right指针移动的单调性,所以可以用滑动窗口来优化,那么时间复杂度降为O(N)。

3.关于怎样计算区间的最小花费

这里引入一个数学问题:在一个数轴上有一些点,如何选取一个位置,使得所有的点到这个位置的距离之和最小?

答案是:选取中间的点,如果点的个数是偶数,那么中间任意两个点都可以。

所以将这个结论应用到这题

a1就是left,a5就是right所指向的位置,那么该区间的最少花费也就是所有点到a3的距离。

如果我们每次都要对每个点都计算的话,那么这里计算的时间复杂度为O(N),因此我们可以使用前缀和,把时间复杂度降为O(1)。

用sum数组代表前缀和数组。

原本求cost的公式化简后,下划线表示的是这个地方可以用前缀和来代替,并且发现了一个规律,其余的部分就是 (a3前有多少个点) * a3 - (a3后有多少个点) * a3 - (前缀和1) + (前缀和2) 

那么此时最小cost的计算公式为:

 这个公式对应了原本求cost化简后的例子。

并且发现其中还有可以化简的地方,我们在代码中体现了。 

代码:

#include <iostream>
#include <algorithm>using namespace std;const int N = 1e5 + 10;long long arr[N];
long long sum[N]; // 前缀和数组
long long n,k;long long cal(int l,int r) // 计算区间的花费
{int mid = l + (r - l) / 2;return (2 * mid - l - r) * arr[mid] - (sum[mid - 1] - sum[l - 1]) + (sum[r] - sum[mid]);
}int main()
{cin >> n >> k;for(int i = 1; i <= n; ++i) // 使用了前缀和,那么下标从1开始比较方便cin >> arr[i];sort(arr + 1,arr + n + 1); // 使得元素之间挨得近for(int i = 1; i <= n; ++i) // 下标从1开始,可以防止越界sum[i] = sum[i - 1] + arr[i]; // 前缀和int left = 1,right = 1;int ret = 1;long long cost; // 区间的所需要花费的次数while(right <= n){// 进窗口cost = cal(left,right);while(cost > k) // 判断{left++; // 出窗口cost = cal(left,right);}//更新结果ret = max(ret,right - left + 1);right++;}cout << ret << endl;return 0;
}

 所以本题的时间复杂度为 O(N logN)主要是排序所消耗的时间。

运用了枚举 + 前缀和 + 滑动窗口 + 贪心。并且还有数学问题的推导,公式的化简。

7.mari和shiny 

 

解法:动态规划

是多状态的线性dp。

其实只要把状态表示想明白就是一道比较简单的dp。

如果我们要找到能组成 ‘shy’的子序列,那么首先得知道有多少个 ‘sh’ 子序列,如果想知道有多少个 ‘sh’子序列,就需要知道有 多少个 's'。

那么就有三个状态,那么就存在三个dp表。

s[i] 表示在[0,i]区间有多少个 's'。

h[i] 表示在[0,i]区间有多少个 'sh'。

y[i]表示在[0,i]区间有多少个'shy'。

因为它的状态转移方程很简单,先填好s表,然后再填h表,最后再填y表,然后返回y表的结果。

所以就不多说了。三次for循环搞定。
另外有一个细节就是初始化,我们可以多开一个格子,方便填表。

还有就是本题数据量比较大,记得用 long long 类型来存。

代码:

#include <iostream>using namespace std;const int N = 3e5 + 10;
long long s[N],h[N],y[N];int main()
{int n;string tmp;cin >> n >> tmp;for(int i = 1; i <= n; ++i){s[i] = s[i - 1];if(tmp[i - 1] == 's')s[i] += 1;}for(int i = 1; i <= n; ++i){h[i] = h[i - 1];if(tmp[i - 1] == 'h')h[i] += s[i];}for(int i = 1; i <= n; ++i){y[i] = y[i - 1];if(tmp[i - 1] == 'y') y[i] += + h[i];}cout << y[n] << endl;return 0;
}

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

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

相关文章

【STM32本科毕业设计】基于STM32的多功能MP3播放器设计

目录 一. 概述二. 系统硬件设计2.1 整体设计思路2.2 硬件器件的选择2.2.1 MP3解码芯片选择 2.2.2 收音机芯片选择2.2.3 温度传感器选择2.2.4 彩灯驱动芯片选择2.2.5 音效处理芯片选择2.2.6 EEPROM芯片选择2.2.7 功率放大芯片选择2.2.8 电源芯片选择2.2.9 人机交互设备选择 2.3 …

map_set(红黑树封装)

1.map和set的整体大致架构 1.map和set的整体 平时我们使用map和set时&#xff0c;头文件是map和set的头文件 set头文件&#xff1a; map头文件 而stl_tree.h代表的就是红黑树 1.2 map和set的大致架构 map和set在源代码基本结构 map的大致特点&#xff1a; set的大致特点&am…

Linux gcc/g++ _ make/makefile

文章目录 库gcc/g程序编译过程链接动态链接静态链接 make _ makefile 库 一、 什么是库&#xff1f; 库是程序代码的集合&#xff0c;是共享程序代码的一种方式。根据源代码的公开情况&#xff0c;库可以分为两种类型&#xff1a; 开源库&#xff0c;公开源代码&#xff0c;能…

SPICE | 常见电路SPICE模型总结

Ref. 1. CMOS VLSI Design: A Circuits and Systems Perspective 目录 0 基础 1 反相器 inverter 2 缓存器 buffer 3 NAND 4 NOR 5 传输门 Transmission gate 6 三态反相器 Tristate Inverter 7 选择器 Multiplexers 8 D锁存器 D Latch 9 D触发器 D Flip-Flop 0 基础…

数模·微分方程

微分方程 核心概念 含导数的方程或方程组 通解和特解的区别&#xff1a;有初值条件的通解称作特解 解析解和数值解的&#xff1a;解析解是通过代数或解析方法得到的精确解。它通常以闭式表达式或公式的形式存在&#xff1b;数值解是通过数值方法&#xff08;如迭代算法&#x…

了解Java虚拟机(JVM)

前言&#x1f440;~ 上一章我们介绍网络原理相关的知识点&#xff0c;今天我们浅浅来了解一下java虚拟机JVM JVM&#xff08; Java Virtual Machine &#xff09; JVM内存区域划分 方法区/元数据区&#xff08;线程共享&#xff09; 堆&#xff08;线程共享&#xff09; 虚…

数据结构——二叉树性质

性质1:在二叉树的第i层上至多有2^(i-1)个结点(i>1)。 这个性质很好记忆&#xff0c;观察一下图6-5-5。 第一层是根结点&#xff0c;只有一个&#xff0c;所以2^(1-1)2^01。 第二层有两个&#xff0c;2^(2-1)22。 第三层有四个&#xff0c;2^(3-1)2^24。 第四层有八个&am…

土地规划与水资源管理:和谐共生,共绘绿色发展的生态蓝图

在快速城市化与气候变化的双重挑战下&#xff0c;土地规划与水资源管理的协同成为了确保可持续发展的关键。本文旨在深入探讨如何将水资源管理融入土地规划的各个环节&#xff0c;以实现资源高效利用与环境的和谐共生。 一、水资源的现状与挑战 全球水资源分布不均&#xff0…

react-native从入门到实战系列教程一环境安装篇

充分阅读官网的环境配置指南&#xff0c;严格按照他的指导作业&#xff0c;不然你一直只能在web或沙箱环境下玩玩 极快的网络和科学上网&#xff0c;必备其中的一个较好的心理忍受能力&#xff0c;因为上面一点就可以让你放弃坚持不懈&#xff0c;努力尝试 成功效果 三大件 …

AI绘画;喂饭进阶!教你如何用Stable Diffusion生成高清建筑手工模型图,一篇文章搞懂什么是Lora模型和CKPT主模型!

前言 刚接触Stable Diffusion不久的你&#xff0c;是否有这样的疑问&#xff1a; Q1: Stable Diffusion中的主模型CKPT是什么&#xff1f; Q2: Stable Diffusion中的Lora模型又是什么&#xff1f; Q3: 在哪儿可以下载好用的AI绘图模型&#xff1f; Q4: Stable Diffusion 如…

Linux---01---安装VMware

一. 什么时Linux Linux 是一个开源的类 Unix 操作系统,Linux 是许多计算机硬件的底层操作系统&#xff0c;特别是服务器、嵌入式系统和个人电脑。它支持多种架构&#xff0c;包括 x86、x64、ARM 和 MIPS 等。Linux 因其稳定性、安全性、开源性以及广泛的社区支持而广受欢迎。 …

【Linux】文件系统|CHS寻址|LBA逻辑块|文件索引|inode|Date block|inodeBitmap|blockBitmap

前言 一个进程通过文件描述符标识一个打开的文件&#xff0c;进程拿着文件描述符可以在内核中找到目标文件进行读写等操作。这是打开的文件&#xff0c;而没有被打开的文件存储在磁盘中&#xff0c;是如何管理的&#xff1f;操作系统在偌大的磁盘中如何找到想要的文件并打开的…

【有哪些GPU算力租用平台值得推荐】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

开放式耳机会成为未来的主流吗?开放式耳机推荐指南

开放式耳机是否会成为未来的主流&#xff0c;是一个值得探讨的问题。 从目前的市场趋势和技术发展来看&#xff0c;有一些因素支持开放式耳机可能成为主流。 一方面&#xff0c;人们对于健康和舒适的关注度不断提高。长时间佩戴传统耳机可能导致耳部不适&#xff0c;而开放式…

java通过poi解析word入门

文章目录 介绍一、了解word docx文档的结构二、引入POI的依赖三、解析Word文档常用API加载Word文档获取文档整体结构获取文档中的段落获取文档中的表格获取文档中的脚注 四、解析Word中的段落示例五、读取Word文档并遍历图片六、解析Word中的图片示例 介绍 Apache POI 是一个处…

AI绘画入门实践|Midjourney:使用 --no 去除不想要的物体

在 Midjourney 中&#xff0c;--no 作为反向提示词&#xff0c;告诉 MJ 在生成图像时&#xff0c;不要包含什么。 使用格式&#xff1a;--no 对应物体提示词&#xff08;多个物体之间使用","间隔&#xff09; 使用演示 a web banner, summer holiday --v 6.0 a web b…

[MySQL][深入理解隔离性][下][Read View]详细讲解

目录 1.Read View1.是什么&#xff1f;2.理解3.整体流程 2.RR与RC的本质区别1.当前读和快照读在RR级别下的区别2.RR与RC的本质区别 1.Read View 1.是什么&#xff1f; Read View就是事务进行 快照读 操作的时候生产的 读视图(Read View)&#xff0c;在该事务执行快照读的那一…

C语言 #指针数组 #数组指针 #数组参数、指针参数

文章目录 前言 一、指针数组 1、概念&#xff1a; 2、指针数组有什么用呢&#xff1f; 二、数组指针 1、数组指针的定义 2、数组名与 &数组名 的区别 3、数组指针如何初始化&#xff1f; 4、数组指针的用法 三、根据代码区分 指针数组 和 数组指针 四、数组参数、指针参数 …

VLAN通讯实验

目录 拓扑图 需求 需求分析 配置过程 1、手工配置 2、 使用DHCP获得IP地址信息 3、测试全网是否可达 拓扑图 需求 1、PC1、PC3属于VLAN 2 2、PC2、PC4属于VLAN 3 3、通过DHCP使得PC获取IP地址信息 4、全网可达 需求分析 1、先手工配置网段&#xff0c;VLAN 2为192.168.1…

在invidia jetpack4.5.1上运行c++版yolov8(tensorRT)

心路历程(可略过) 为了能在arm64上跑通yolov8,我试过很多很多代码,太多对库版本的要求太高了; 比如说有一个是需要依赖onnx库的,(https://github.com/UNeedCryDear/yolov8-opencv-onnxruntime-cpp) 运行成功了报错error: IOrtSessionOptionsAppendExecutionProvider C…