1.TCP的握手和挥手
我是画了3次握手和4次挥手的原理图,不过seq没标,后来面试官叫我加了
从网上找的示意图,每次ack都是seq加发送的数据包个数。
2.进程间和线程间的通信和同步?
进程通信:无名管道、有名管道、信号、信号量、消息队列、共享内存和套接字(socket)
线程同步:条件变量、互斥锁、读写锁、信号量
3.什么是事务以及事务的特性(这个是真的懵逼,以前没听过这个概念)
事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消。也就是事务具有原子性,一个事务中的一系列的操作要么全部成功,要么一个都不做。
(1)原子性:整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
(2)一致性:在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。
(3)隔离性:隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行 相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆, 必须串行化或序列化请 求,使得在同一时间仅有一个请求用于同一数据。
(4)持久性:在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
4.什么是多播(组播)和广播,各自的优劣性。(当时自己答的不详)
多播:
主机之间一对一组的通讯模式,也就是加入了同一个组的主机可以接受到此组内的所有数据,网络中的交换机和路由器只向有需求者复制并转发其所需数据。
优点:具备广播的优点,而且是有选择的发送数据,节省了服务器的负担。允许在Internet宽带网上传输。
缺点:没有纠错机制,只能靠应用层做一些处理去容错。客户认证和服务质量(qos)需要改善。
组播:
主机之间一对所有的通讯模式,网络对其中每一台主机发出的信号都进行无条件复制并转发,所有主机都可以接收到所有信息(不管你是否需要)。
优点:网络设备简单,维护简单,布网成本低廉,由于服务器不用向每个客户机单独发送数据,所以服务器流量负载极低。
缺点:无法针对每个客户的要求和时间及时提供个性化服务。广播禁止允许在Internet宽带网上传输。
5. 删除两个双向循环链表中具有相同值的节点
我的第一想法是2个链表排序,然后再删除,这样会破坏链表顺序,不太好,写了思路。
第二个想法是用一个map来辅助,先遍历第一个链表,再遍历第二个链表找出map中有的,然后再分别删除2个链表中有这些值的结点。刚开始写面试官就来了…好想把想法写出
以下是第二种的实现:
void DeleteCommonNode(Node *&pHeadA, Node*&pHeadB)
{
if(pHeadA == NULL || pHeadB == NULL)
return ;
map<int,Node *> hmap;//想解决单一链表中重复的话要有multimap
Node *tmp = pHeadA;
while(tmp)
{
hmap[tmp->data] = tmp;
tmp = tmp->next;
}
Node* tmpb = pHeadB;
int flag = hmap.size(), iCount = 0;
while(tmpb && hmap.size() > 0)
{
iCount++;
if(flag == iCount)
{
if(tmpb == pHeadB)
break;//如果循环了一遍还是这几个节点
flag = hmap.size();
iCount = 1;
}
if(hmap[tmpb->data] != NULL)
{
//删除链表B中的这个节点
Node *pTempb = tmpb;
pTempb->front->next = pTempb->next;
pTempb->next->front = pTempb->front;
delete pTempb;
Node *tmpa = hmap[tmpb->data];
hmap.erase(tmpa->data);//从map中把去重的删除
//删除链表A中的相同节点
Node *pTempA = tmpa;
pTempA->front->next = pTempA->next;
pTempA->next->front = pTempA->front;
delete pTempA;
}
tmpb = tmpb->next;
}
}
/*没有实证过,不一定对,仅供参考*/
6. 1000个苹果放入10个箱子。客户如果要获得1~1000个苹果中的任意个数,都可以整箱搬,而不用拆开箱子。问是否有这样的装箱方法?(我没想出来,当时还在想怎么可能,尴尬)
二进制数组合:
1
10
100
1000
可以表示任何0X01~0XFF之间的数字,所以按照这样的思想,
1
10
100
1000
10000
100000
1000000
10000000
100000000
1000000000
可以表示任何1~0X10FF的数,即1~1024的数,而一共只有1000个苹果,所以数列应该为
1, 2, 4, 8, 16, 32, 64, 128, 256, 489
膜拜各位大佬,我是真想不出来,看答案就一目了然了,哈哈,菜是原罪
7. 小易觉得高数课太无聊了,决定睡觉。不过他对课上的一些内容挺感兴趣,所以希望你在老师讲到有趣的部分的时候叫醒他一下。你知道了小易对一堂课每分钟知识点的感兴趣程度,并以分数量化,以及他在这堂课上每分钟是否会睡着,你可以叫醒他一次,这会使得他在接下来的k分钟内保持清醒。你需要选择一种方案最大化小易这堂课听到的知识点分值。
输入描述:
第一行 n, k (1 <= n, k <= 105) ,表示这堂课持续多少分钟,以及叫醒小易一次使他能够保持清醒的时间。
第二行 n 个数,a1, a2, … , an(1 <= ai <= 104) 表示小易对每分钟知识点的感兴趣评分。
第三行 n 个数,t1, t2, … , tn 表示每分钟小易是否清醒, 1表示清醒。
输出描述:
小易这堂课听到的知识点的最大兴趣值。
示例1
输入
6 3
1 3 5 2 5 4
1 1 0 1 0 0
输出
16
思路:首先在输入ti的同时先计算出ti1的兴趣和,然后再遍历一遍兴趣数组a,暴力计算其中每k个ti为0的兴趣和,记录下最大值,加上之前的ti1的兴趣和即可
抄了一份代码:https://blog.csdn.net/qq_43069546/article/details/100511791
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int n,k;
cin>>n>>k;
int* a=new int [n+1];
int* t=new int [n+1];
vector<int> record;
long long ans=0;
for(int i=1;i<=n;++i)
cin>>a[i];
for(int i=1;i<=n;++i)
{
cin>>t[i];
if(t[i])//这里就统计清醒时的分数
ans+=a[i];
else
record.push_back(i);
}
if(n<=k)
{//如果叫醒一次可以醒一堂课,那全部加上
int sum=0;
for(int i=1;i<=n;++i)
sum+=a[i];
cout<<sum<<endl;
}
else
{
long long maxTemp=0;
for(int i=0;i<record.size();++i)
{
long long temp=0;
//看从这一点开始到k-1分钟,有没有超过尾端
int end=(record[i]+k-1>n) ? n : record[i]+k-1;
for(int j=record[i];j<=end;++j)
{//计算这一点到后面的k-1分钟的总分数,只统计睡觉的
if(!t[j]) temp+=a[j];
}//maxTemp记住最大值
maxTemp=max(maxTemp,temp);
}
ans+=maxTemp;
delete[] a;
delete[] t;
cout<<ans<<endl;
}
return 0;
}