记录2023.4.14晚7.00-9.00腾讯面试

一个小时做题

四道算法题

1、检测是否为合法的字符串括号?

用的是栈数据结构,遇到)]  } 和栈顶元素不能消除就return false。

2、检测数组中出现两次的元素?leetcode442题

第一种方法是将num[i]和num[num[i]-1]交换位置,然后如果这两者相等,就说明元素出现了两次;第二种方法就是在遍历num[i]时,将num[num[i]-1]置为负数。

3、将链表中的奇偶位置分类,奇数位置放在前面,偶数位置放在后面并保持原来顺序不变

将奇偶第一个位置的节点保存,其次使用两个指针指向这两个节点,然后通过这两个指针重新指向下两个位置的节点,到了最后,就把链表分为了两部分,最后把两部分的头结点连接起来。

4、LRU缓存

使用一个双向链表和一个哈希表完成,双向链表中需要记录哈希表的键值对。

一个小时问答

1、C++中的短路求值?

逻辑与和逻辑或操作符总是先计算其左操作数,然后再计算其右操作数。只有在仅靠左操作数的值无法确定该逻辑表达式的结果时,才会求解其右操作数。我们常常称这种求值策略为”短路求值”。

为什么要短路求值

1、提高程序的运行效率:能够通过左操作数就确定逻辑表达式的结果不计算右操作数降低了程序计算量,提高程序效率;

2、防止出现难以预料的后果;

3、代码的逻辑更为紧密。

2、C++的中sizeof?

在c99没有出现之前,sizeof是由编译时确定的;c99中引入了动态数组(定义一个数组,其大小由运行时确定) 导致sizeof作用于动态数组时的值不再是常量。

其次int a[10],sizeof(a)是等于40的;若是int *p,sizeof(p)=8(64位系统);

char 1;short 2;int 4;long 4;float 4;double 8;pointer 8;

3、struct和class中的sizeof?

空类和空结构体中的大小是1字节,在C++中空类会占一个字节,这是为了让对象的实例能够相互区别。具体来说,空类同样可以被实例化,并且每个实例在内存中都有独一无二的地址,因此,编译器会给空类隐含加上一个字节,这样空类实例化之后就会拥有独一无二的内存地址。如果没有这一个字节的占位,那么空类就无所谓实例化了,因为实例化的过程就是在内存中分配一块地址。

实际的大小根据字节对齐,注意定义变量顺序和最大变量字节对齐。

对于类来说,虚函数表和虚函数指针的存在会使虚函数指针占8个字节。

注意继承问题。

3、链表和数组的复杂度问题?

数组:随机访问的时间复杂度为O(1);

            删除末尾元素和在末尾增加元素(空间充足)时间复杂度为O(1);

            插入和删除时间复杂度为O(n);

            查找指定元素时间复杂度为O(n);

链表:添加删除头尾几点的时间复杂度为O(1);

            添加删除到链表指定节点时间复杂度为O(n);

           查找指定元素或者指定位置节点时间复杂度为O(n);

哈希表:查找插入时间复杂度为O(1);

4、哈希表的存储空间是连续的吗?哈希冲突以及如何解决?

        采用散列技术将记录存储在一块连续的存储空间中,Hash在存储数据的时候是非连续存储的,通过Hash函数在索引值与数据之间建立映射关系,查找或存储的时候通过关键字和Hash函数来进行。

        哈希表的空间是连续的,但是其元素存储的位置是非连续的。

        哈希冲突:在理想的情况下,每一个关键字,通过哈希函数计算出来的地址都是不一样的。但是在实际情况中,我们常常会碰到两个关键字key1≠key2,但是f(key1) = f(key2), 这种现象称为冲突,并把key1和key2称为这个散列函数的同义词。

哈希冲突不能避免,主要有4种解决办法:
        开放地址法:
一旦发生了冲突就去寻找下一个空的哈希地址,只要哈希表足够大,空的散列地址总能找到,并将记录存入。
        再哈希法:
当哈希冲突时,使用不同的哈希函数计算地址,直到不冲突为止。这种方法不易产生堆积,但是耗费时间。
        链地址法:
产生哈希冲突的关键字记录存储在一个单链表中,我们称这种单链表为同义词子表,散列表中存储同义词子表的头指针。
链地址法解决了冲突,提供了永远都能找到地址的保证。但也带来了查找时需要遍历单链表的性能,HashMap >8 转换为红黑树。
        公共溢出区法:
即设立两个表:基础表和溢出表。将所有关键字通过哈希函数计算出相应的地址。然后将未发生冲突的关键字放入相应的基础表中,一旦发生冲突,就将其依次放入溢出表中即可
查找时,先用给定值通过哈希函数计算出相应的散列地址后,首先与「基本表」的相应位置进行比较,如果不相等,再到「溢出表」中顺序查找。

5、进程和线程的区别?适用于哪种场景?

线程:

Linux下线程用进程PCB模拟描述,也叫轻量级进程

线程是进程内部的一个执行流,也就是线程在进程的地址空间内运行。

一个进程内的所有线程共享进程资源

线程是CPU调度的基本单位(CPU调度是按照PCB进行调度的)

创建,销毁一个线程相较创建,销毁一个进程成本要低(创建进程要创建PCB,虚拟地址空间,创建页表,维护映射,把硬盘的代码数据加载到内存,文件描述符等等,而创建线程只需要一个PCB指向进程的虚拟地址空间即可,同样销毁一个线程只需要销毁PCB即可)

线程间的切换相比于进程间的切换容易的多(进程间的切换,PCB切换,页表切换等等,线程切换PCB切换,页表不切换)
进程:

进程是拥有一个执行流,或多个执行流的线程组。

进程是一个能独立运行的基本单位,同时也是系统分配资源基本单位。(独立性)

进程是动态执行的程序(创建一个进程要创建PCB描述进程,为进程分配资源,进程可以被调度,被执行。而程序就只是静静躺在硬盘上)(动态性)

任何进程都可以同其他进程一起并发执行(并发性)(并发:一个CPU多个进程,分时切换)

进程间的相互制约,进程具有执行的间断性,进程按照各自独立不可预知的速度向前推进(异步性)(异步性:指进程以不可预知的速度向前推进,内存中的每个进程何时执行,何时暂停,以怎样的速度向前推进,要用多长时间完成等都是不可预知的)
区别:

线程是被CPU调度的基本单位,进程是能独立运行的基本单位,是系统分配资源的基本单位

创建销毁线程要比创建销毁进程成本低的多。(创建进程要,创建PCB,开辟虚拟地址空间,创建页表,维护映射关系,加载硬盘数据到内存,创建文件描述符,等等,而创建线程只要创建一个PCB指向进程的虚拟地址空间即可)

进程拥有自己独立的虚拟地址空间,而一个进程中的多个线程共享进程的虚拟地址空间

线程占用的资源要比进程少

线程缺乏访问控制,进程中的一个线程出错,会终止掉整个进程,从而导致其他线程也凉凉,而一个进程出错,不会影响另一个进程

使用场景:

1、需要频繁创建销毁的优先使用线程;因为对进程来说创建和销毁一个进程代价是很大的。

2、线程的切换速度快,所以在需要大量计算,切换频繁时用线程,还有耗时的操作使用线程可提高应用程序的响应

3、因为对CPU系统的效率使用上线程更占优,所以可能要发展到多机分布的用进程,多核分布用线程;

4、并行操作时使用线程,如C/S架构的服务器端并发线程响应用户的请求;

5、需要更稳定安全时,适合选择进程;需要速度时,选择线程更好。

6、操作系统的堆栈?

栈:

执行期间编译器自动分配,编译器用它实现函数调用,调用函数时,栈增长,函数返回时,栈收缩。局部变量、函数参数、返回数据、返回地址等放在栈中。

栈的特点

  1. 内存分配取决于编译器,用户栈在程序运行期间可以动态的扩展和收缩。
  2. 和数据结构中的“栈”本质上是不一样的,但是操作方式类似于栈。
  3. 数据从栈中的进出满足“后进先出”的规律。
  4. 栈向低地址方向增长,esp(栈指针)指向栈顶元素。

堆:

动态储存器分配器维护着的一个进程的虚拟存储器区域。一般由程序员分配释放(堆在操作系统对进程初始化的时候分配),若程序员不释放,程序结束时可能由OS回收,每个进程,内核都维护着一个变量brk指向堆顶。

堆的特点

  1. 内存分配取决于程序员,C/C++可以手动释放该片内存。
  2. 和数据结构的”堆“完全两回事,没有半点关系,在这里堆的结构更像链表。
  3. 所有的对象,包括数组的对象都存在堆上。
  4. 堆内存被所有的线程共享。
  5. 引用类型总是放在堆中。
  6. 堆向高地址方向增长,内核都维护的变量brk指向堆顶。

栈和堆的区别:

  1. 栈内存存储的的是局部变量,堆内存存储的是实体。
  2. 栈内存的更新的速度会更快些(局部变量),堆内存的更新速度相对更慢。
  3. 栈内存的访问直接从地址读取数据到寄存器,然后放到目标地址,而堆内存的访问更麻烦,先将分配的地址放到寄存器,在读取地址的值,最后再放到目标文件中,开销更大。
  4. 栈内存是连续的空间,堆内存一般情况不是连续的,频繁地开辟空间,释放空间容易产生内存碎片(外碎片)。

 7、为什么OSI分为7层和五层?

OSI(开放式系统互连参考模型)最初定义了一个七层的网络架构,这七层从底层到顶层依次是:物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。

但是在实际应用中,由于一些层之间的功能重叠,使得该模型不够简洁实用,同时也存在一些问题,例如难以区分应用层和表示层之间的边界等。因此,人们逐渐提出了一些简化版的模型,如TCP/IP模型、五层模型等。

其中,五层模型包括物理层、数据链路层、网络层、传输层和应用层,将原来的会话层和表示层合并到了应用层中,同时将物理层和数据链路层合并成一个层次结构,主要目的是为了简化通信协议的设计和实现,提高网络通讯的效率。

总之,OSI的七层模型和五层模型都有其优点和缺点,选择使用哪种模型应该根据具体情况而定。

8、应用层的rtsp视频流协议基于什么协议?

应用层的RTSP(Real Time Streaming Protocol,实时流传输协议)基于HTTP协议。RTSP是一种网络应用层协议,用于控制多媒体服务器上的音视频流,并允许客户端通过网络与多媒体服务器进行交互。RTSP中定义了一些命令和响应报文,用于控制和监控视频流的传输,而HTTP协议则提供了连接管理、数据传输等基本功能,因此RTSP协议可以利用HTTP协议的优点来建立和控制实时视频传输连接。同时,RTSP也可以与其他互联网协议结合使用,如RTP(Real-time Transport Protocol,实时传输协议)等,以实现高效的实时视频传输。

9、token、cookie、session?

HTTP 协议是一种无状态协议,即每次服务端接收到客户端的请求时,都是一个全新的请求,服务器并不知道客户端的历史请求记录;Session 和 Cookie 的主要目的就是为了弥补 HTTP 的无状态特性。

Session 是什么

客户端请求服务端,服务端会为这次请求开辟一块内存空间,这个对象便是 Session 对象,存储结构为 ConcurrentHashMap。Session 弥补了 HTTP 无状态特性,服务器可以利用 Session 存储客户端在同一个会话期间的一些操作记录。

session

  • 会话,代表服务器与浏览器的一次会话过程,这个过程是连续的,也可以时断时续。
  • cookie中存放着一个sessionID,请求时会发送这个ID;
  • session因为请求(request对象)而产生;
  • session是一个容器,可以存放会话过程中的任何对象;
  • session的创建与使用总是在服务端,浏览器从来都没有得到过session对象;
  • session是一种http存储机制,目的是为武装的http提供持久机制。

Cookie是什么

HTTP 协议中的 Cookie 包括 Web Cookie浏览器 Cookie,它是服务器发送到 Web 浏览器的一小块数据。服务器发送到浏览器的 Cookie,浏览器会进行存储,并与下一个请求一起发送到服务器。通常,它用于判断两个请求是否来自于同一个浏览器,例如用户保持登录状态。cookie 是一个非常具体的东西,指的就是浏览器里面能永久存储的一种数据,仅仅是浏览器实现的一种数据存储功能。sessionId 通常是存储在 cookie 中。

会话 Cookies

上面的示例创建的是会话 Cookie ,会话 Cookie 有个特征,客户端关闭时 Cookie 会删除,因为它没有指定ExpiresMax-Age 指令。

但是,Web 浏览器可能会使用会话还原,这会使大多数会话 Cookie 保持永久状态,就像从未关闭过浏览器一样。

永久性 Cookies

永久性 Cookie 不会在客户端关闭时过期,而是在特定日期(Expires)特定时间长度(Max-Age)外过期。

token是什么?

        服务器存储sessionn id不好,就让每个客户端保存,比如说, 小F已经登录了系统, 我给他发一个令牌(token), 里边包含了小F的 user id, 下一次小F 再次通过Http 请求访问我的时候, 把这个token 通过Http header 带过来不就可以了。

        对数据做一个签名防止伪造, 比如说我用HMAC-SHA256 算法,加上一个只有我才知道的密钥, 对数据做一个签名, 把这个签名和数据一起作为token , 由于密钥别人不知道, 就无法伪造token了。

 其实 token 和 session 的验证机制最大的区别是用“签名验证机制”代替了“白名单验证机制”。

 token 里面一般都会放上 user_id,否则就得到服务器维护一个 token 到 user_id 的映射

总结下来就是:session 是空间换时间,token 是时间换空间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值