【复盘#01】myh笔试
存疑
1、http响应体中版本和缓存是哪个字段(Etga)
http和https的区别
2、mysql同一个表中有多个相同字段但搜索的时候只搜得出某一个,要怎么修改(inner 。。)
mysql如何降序排序
3、磁盘读取数据如何最快,位置分别是130、140、160、180、200
4、vector特点的相关知识(内存连续、随机读取、不能存什么东西等)
5、分组数据的输入处理
编程题
1、分组数据的输入处理(打卡题)
题意
给t个对话,每个对话由n对字符串组成。按照从左到右的顺序,如果两个字符串相同则分数+1,否则-1
如果分数为负,为无效对话。求:有效对话的数量
思路
#include <iostream>
#include <vector>
using namespace std;
int main(){
int t;//题目给了输入的数量,即在输入中明确指定了 t 的值
cin >> t;//因此直接接收t,不用while
int n;
string s;
int res = 0;
for(int i = 0; i < t; ++i){//循环t次,处理每个对话
cin >> n;//n对字符串也是明确给出的
vector<string> hash;
for(int j = 0; j < n; ++j){//循环n次接收n个字符串s(丘丘人输入)
cin >> s;
hash.push_back(s);//将每个字符串加入vector中
}
int score = 0;//用于记录
bool flag = true;
for(int j = 0; j < n; ++j){//循环处理n次处理n对字符串(我的回答)
cin >> s;
if(s == hash[j]) score++;//输入与hash中匹配,更新score的值
else score--;
if (score < 0) flag = false;
}
if(flag) score++;
}
cout << res << '\n';
return 0;
}
这里一开始以为要全匹配才算,结果是只要有部分匹配就行(错两次就不行了),还以为是测试用例给错了。。。
2、
3、最小未知树的权值之和(LeetCode1949)
给定一棵有n个节点的有根树,根节点为 1号节点,1号节点的深度为1,树上每一个节点都有一个不完美值。整棵树的不完美值是树上每一个节点的不完美值乘上这个节点的深度之和。米小游可以把一棵子树切断,再把这棵子树拼接在一个节点上,使得整棵的不完美值最小。
求这棵树最小的不完美值。
输入描述
第一行输入一个整数n(1<=n<=10^5)表示树的大小。
第二行输入n个整数a(1<=ai<=10^8)表示每个节点的不完美值。
接下来n-1行,每行输入两个整数u,v(1<=u,v<=n),表示树上的边。
输出描述
输出一个整数表示最小的不完美值。
示例1
输入
3
1 2 3
1 2
2 3
输出
11
说明
初始时,树的不完美值是:1*1+2*2+3*3=14
把以节点3为根的子树切断,再拼接到节点1上,树的
不完美值是:1*1+2*2+3*2=11。
可以证明,没有更小的不完美值。
思路与代码
这里有以下几个迷惑点
1、所给示例的树的结构
根据说明,其实可以想象出树的大致结构如下:
1
\
2
/
3
这是符合初始时不完美值的计算公式的
然后需要把3移动到1下,这样得到更小的不完美值
1
/ \
3 2
2、如何表示(存储)一棵树以及如何使用邻接表进行DFS
因为我几乎没有做过图论的相关题目(在ACM模式下)。因此我不知道应该如何保存一个输入的树
经过搜索得知,一般一个树输入后会使用邻接表进行存储
3、代码
这里涉及到如何处理图的输入,有一定的参考价值
#include <iostream>
#include <vector>
using namespace std;
vector<vector<int>> graph;
vector<int> path;
int n;
int res, val;
int dfs_getvals(int node, int pre, int depth) {
int cur = path[node] * depth;
for (int next : graph[node]) {//从节点列表中取当前节点连接的下一个节点值
if (next != pre) {
cur += dfs_getvals(next, node, depth + 1);
}
}
return cur;
}
void dfs(int node, int pre, int depth) {
int cur = path[node];
for (int next : graph[node]) {
if (next != pre) {
cur += dfs(next, node, depth + 1);
}
}
res = min(res, val - cur * (depth - 2));
}
int main() {
cin >> n;//获取输入的节点数
graph.resize(n + 1);//初始化邻接表大小
path.resize(n + 1);//初始化路径数组大小
for (int i = 1; i <= n; i++) {
cin >> path[i];//路径是输入的,需要获取
}
for (int i = 0; i < n - 1; i++) {
int u, v;//通过输入构造图,具体细节见图论说明
cin >> u >> v;
graph[u].push_back(v);
graph[v].push_back(u);
}
//先调用一次dfs计算每个节点的不完美值
res = dfs_getvals(1, -1, 1);
val = res;
dfs(1, -1, 1);//再进行一次dfs选择出每个节点的最小不完美值,并更新到res中
cout << res << endl;
return 0;
}
与单纯的遍历图结构相比,这里多加了一个判断当前节点是否为父节点的逻辑。
举个例子,假设输入的树结构为:
1 / \ 2 3
如果没有加上
if (next != pre)
,在遍历节点1时,会递归遍历节点2和3。而在遍历节点2时,会再次递归遍历节点1,形成了一个环路。这样的话,程序会进入无限循环,最终导致栈溢出或死循环。(单纯遍历图时到2或3就已经触发终止条件了)通过加上
if (next != pre)
的判断条件,可以避免在DFS过程中重复遍历已经访问过的节点,从而避免形成环路,并确保对每个节点只进行一次遍历。
知识补充
http响应体信息
在HTTP响应体中,版本信息和缓存相关的字段分别是:
- 版本信息:HTTP协议版本信息通常包含在响应头(Response Header)中的"HTTP/1.1"或"HTTP/2"等字段中。这个字段指示了服务器使用的HTTP协议版本。
- 缓存相关字段:HTTP响应头中包含了一些与缓存相关的字段,主要用于控制客户端或代理服务器对资源的缓存行为。具体的缓存相关字段包括:
- Cache-Control:用于控制缓存行为,可以设置缓存的过期时间、是否允许缓存、是否允许缓存更新等。
- Expires:指定资源的过期时间,告诉客户端在该时间之后需要重新获取资源。
- ETag:表示资源的实体标签,用于判断资源是否发生变化,从而控制缓存的有效性。
- Last-Modified:指定资源的最后修改时间,也是用于判断资源是否发生变化的依据。
- If-Modified-Since:客户端通过该字段指定一个时间,如果资源在该时间之后没有发生修改,则返回状态码304,表示资源未改变,可以使用缓存副本。
http和https的区别
HTTP(HyperText Transfer Protocol,超文本传输协议)和HTTPS(HyperText Transfer Protocol Secure,安全的超文本传输协议)是用于在客户端和服务器之间进行数据传输的协议。它们的主要区别如下:
- 安全性:HTTP是明文传输的协议,数据在传输过程中不进行加密,容易被拦截和窃取。而HTTPS通过使用SSL/TLS加密协议对数据进行加密,确保数据的安全性和完整性,防止被第三方窃听和篡改。
HTTP容易遭到中间人攻击
中间人攻击的常见方式包括:
- ARP欺骗(ARP spoofing):攻击者通过伪造网络设备的ARP响应,将通信的两端的流量重定向到攻击者控制的设备上。
- DNS劫持(DNS hijacking):攻击者通过篡改DNS服务器的响应,将用户的域名解析请求重定向到攻击者控制的恶意服务器上。
- SSL剥离(SSL stripping):攻击者将HTTPS请求转发到HTTP请求,使得通信变为明文传输,从而截获和篡改通信内容。
- 默认端口:HTTP使用的默认端口是80,而HTTPS使用的默认端口是443。在浏览器中访问网站时,如果使用HTTP协议,默认会使用80端口,如果使用HTTPS协议,则默认会使用443端口。
- 证书:HTTPS需要使用数字证书来验证服务器的身份,并且建立安全连接。数字证书由可信任的第三方机构(如CA,Certificate Authority)签发,用于确认服务器的真实性。而HTTP不需要使用数字证书。
- 连接方式:HTTP是无连接的协议,即每次请求都是独立的,不会保留连接状态。每个请求都会建立一个新的连接,并在请求完成后立即关闭连接。而HTTPS使用SSL/TLS协议建立安全连接,在完成请求后保持连接,可以多次请求复用连接。
MySQL中的表连接操作
在MySQL中,表连接操作用于将两个或多个表中的数据关联起来,以便根据指定的连接条件获取合并后的结果集。表连接操作有几种不同的类型,包括内连接(INNER JOIN
)、左连接(LEFT JOIN
)、右连接(RIGHT JOIN
)和全连接(FULL JOIN
)。这些连接操作可以帮助我们在多个表之间建立关系,进行复杂的数据查询和分析。
下面我将介绍每种表连接操作,并提供一些示例说明:
-
内连接(
INNER JOIN
):内连接返回两个表中满足连接条件的匹配行。只有在连接条件匹配的情况下,才会返回结果。示例:假设有两个表,
orders
和customers
,它们通过共同的列customer_id
进行连接。以下查询将返回同时存在于两个表中的匹配行:SELECT * FROM orders INNER JOIN customers ON orders.customer_id = customers.customer_id;
-
左连接(
LEFT JOIN
):左连接返回左表中的所有行,以及与右表中满足连接条件的匹配行。如果右表中没有匹配的行,则结果中的右表列将包含 NULL 值。示例:假设有两个表,
orders
和customers
,它们通过共同的列customer_id
进行连接。以下查询将返回左表orders
中的所有行,并与右表customers
中满足连接条件的行进行匹配:SELECT * FROM orders LEFT JOIN customers ON orders.customer_id = customers.customer_id;
-
右连接(
RIGHT JOIN
):右连接返回右表中的所有行,以及与左表中满足连接条件的匹配行。如果左表中没有匹配的行,则结果中的左表列将包含 NULL 值。示例:假设有两个表,
orders
和customers
,它们通过共同的列customer_id
进行连接。以下查询将返回右表customers
中的所有行,并与左表orders
中满足连接条件的行进行匹配:SELECT * FROM orders RIGHT JOIN customers ON orders.customer_id = customers.customer_id;
-
全连接(
FULL JOIN
):全连接返回左表和右表中的所有行,无论是否满足连接条件。如果某个表中没有匹配的行,则结果中的对应列将包含 NULL 值。示例:假设有两个表,
orders
和customers
,它们通过共同的列customer_id
进行连接。以下查询将返回左表orders
和右表customers
中的所有行,并根据连接条件进行匹配:SELECT * FROM orders FULL JOIN customers ON orders.customer_id = customers.customer_id;
MySQL中的降序排序
在MySQL中,可以使用 ORDER BY
子句对查询结果进行降序排序。ORDER BY
子句允许指定一个或多个列作为排序条件,并使用 DESC
关键字表示降序排序。
以下是一些示例说明如何在MySQL中进行降序排序:
-
单列降序排序:假设有一个名为
products
的表,其中包含product_id
和product_name
列。以下查询将按照product_id
列的降序对结果进行排序:SELECT * FROM products ORDER BY product_id DESC;
上述查询将返回按照
product_id
列降序排列的所有行。 -
多列降序排序:可以使用多个列作为排序条件。假设在上述的
products
表中,还有一个price
列,以下查询将首先按照price
列降序排序,然后在相同price
值的情况下按照product_id
列降序排序:SELECT * FROM products ORDER BY price DESC, product_id DESC;
上述查询将返回按照
price
列降序排列,并在相同price
值的情况下按照product_id
列降序排列的所有行。 -
字符串降序排序:对于字符串列,降序排序将按照字母逆序排列。假设有一个名为
users
的表,其中包含user_id
和username
列。以下查询将按照username
列的降序对结果进行排序:SELECT * FROM users ORDER BY username DESC;
上述查询将返回按照
username
列降序排列的所有行。 -
聚合函数与降序排序:可以将聚合函数与降序排序结合使用。假设有一个名为
orders
的表,其中包含order_id
和total_amount
列。以下查询将按照total_amount
列的降序对结果进行排序,并计算总金额的最大值:SELECT MAX(total_amount) AS max_amount FROM orders ORDER BY total_amount DESC;
上述查询将返回按照
total_amount
列降序排列的所有行,并计算出最大的总金额。
MAX
函数本身并不能直接实现降序排序,因为它是用于计算指定列的最大值,而不是对整个结果集进行排序。如果你想要在查询中同时使用
MAX
函数和降序排序,可以结合使用ORDER BY
子句来实现。首先使用MAX
函数计算最大值,然后使用ORDER BY
子句对结果进行降序排序。以下是一个示例,展示如何使用
MAX
函数和降序排序:假设有一个名为
products
的表,其中包含product_id
和price
列。你可以使用以下查询来获取价格最高的产品:SELECT product_id, price FROM products WHERE price = (SELECT MAX(price) FROM products) ORDER BY price DESC;
上述查询中,子查询
SELECT MAX(price) FROM products
用于获取price
列的最大值。然后,在外部查询中,使用WHERE
子句筛选出价格等于最大值的产品,并使用ORDER BY
子句对结果按价格降序排序。
磁盘寻道方法
考到了"最短寻道时间优先"(Shortest Seek Time First,SSTF),这里需要补充一下知识
例题1:
假设磁盘磁头当前位于100,需要读取的磁道位置分别为30、60、90、120、150。使用SSTF策略,磁头应该按照以下顺序读取数据:
- 从当前位置100开始,找到距离最近的磁道,即90。
- 读取90磁道的数据。
- 接下来,找到距离90最近的磁道,即60。
- 读取60磁道的数据。
- 继续找到距离60最近的磁道,即30。
- 读取30磁道的数据。
- 向外移动到距离30最近的磁道,即120。
- 读取120磁道的数据。
- 最后,移动到距离120最近的磁道,即150。
- 读取150磁道的数据。
所以,按照SSTF策略,磁头的读取顺序为:100 -> 90 -> 60 -> 30 -> 120 -> 150。
例题2:
假设磁盘磁头当前位于45,需要读取的磁道位置分别为10、20、40、70、80。使用SSTF策略,磁头应该按照以下顺序读取数据:
- 从当前位置45开始,找到距离最近的磁道,即40。
- 读取40磁道的数据。
- 接下来,找到距离40最近的磁道,即20。
- 读取20磁道的数据。
- 继续找到距离20最近的磁道,即10。
- 读取10磁道的数据。
- 向外移动到距离10最近的磁道,即70。
- 读取70磁道的数据。
- 最后,移动到距离70最近的磁道,即80。
- 读取80磁道的数据。
需要注意的是,实际的磁盘读取速度还受到磁盘驱动程序和操作系统的调度策略等因素的影响。此外,如果磁盘上的数据是连续存储的,顺序读取会比随机读取更快。因此,以上所述的读取顺序是在假设数据在磁盘上是按照位置顺序存储的情况下给出的最佳推荐顺序。
vector特点
1、vector在堆中使用连续内存空间存放元素;
2、如果当前的vector已经满了,在新增数据时就要开辟一块新的内存
3、支持随机读取
数组(array):数组是一种连续存储元素的容器,支持随机读取。由于数组的元素在内存中是连续存储的,可以通过下标直接访问特定位置的元素,因此具有较快的随机读取速度。
向量(vector):向量是动态数组,也支持随机读取。向量的底层实现与数组类似,即使用连续的内存块存储元素,因此同样可以通过下标进行随机访问。
链表(list):链表不支持随机读取。链表中的元素是通过指针连接起来的,每个元素只包含了下一个元素的地址,无法通过下标直接访问某个特定位置的元素。需要从头节点开始顺序遍历链表才能找到目标位置的元素。
双向链表(deque):双向链表是一种支持双向遍历的容器,也可以通过迭代器实现随机访问。因为双向链表中的每个元素都保存了前驱和后继节点的指针,通过迭代器可以在常数时间内实现前移和后移操作,从而实现随机读取。
映射(map)和集合(set):映射和集合是基于红黑树实现的,也支持随机读取。红黑树是一种自平衡的二叉搜索树,它具有良好的平衡性质,可以在对数时间内完成查找操作。
总结起来,数组、向量、双向链表、映射和集合都支持随机读取。只有链表不支持随机读取,需要顺序遍历才能访问特定位置的元素。
4、vector不可以存放引用类型以及具有特殊限制的对象
引用类型:因为引用必须初始化,并且无法更改引用的目标,而vector的元素可以动态添加和删除,所以无法存储引用类型。
具有特殊限制的对象:某些对象可能具有特殊的复制或移动语义,例如禁止复制或只能移动的对象,对于这些对象,使用vector可能会导致不可预期的行为。