C++面经总结3

寻找前K个高频的数字

解题思路 : 先用map去统计次数, 然后用multimap根据次数排序, 返回前K个高频的即可

题目链接 力扣347

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) 
    {
        map<int, int> m1;   //统计次数
        for(auto e : nums)
             m1[e]++;
        
        multimap<int, int, greater<int>> m2;  //根据次数降序排序,次数可能相同
        for(auto e : m1)
        {
            m2.insert({e.second, e.first});
        }
        
        vector<int> v;
        for(auto e : m2)
        {
            if(k == 0)
                break;
            
            k--;
            v.push_back(e.second);
        }
        
        return v;
    }
};

对shell命令了解吗?

ll , ls , mkdir, mv, netstat, grep, cp, cd, rm, chmod, ln, ,

找到服务a的运行目录所涉及的命令?

netstat -nltp | grep a //找到对应的pid
ll /proc/pid/exe

找访问的某个ip端口的top5的ip地址命令

netstat -nltp | grep IP + 端口号 | head -5

sql语句发现运行慢,如何优化

1,对于经常被查询或用于排序或者连表查询的字段, 应该建立索引。
2, 多建立联合索引而不是单列索引,多个单列搜索比一个联合索引更浪费空间。
3, 尽量利用索引, 尽量避免 前置% 和 后置%的一起使用。
4, 尽量避免使用 select * from 表名, 应该需要哪些字段就查询哪些字段。

websocket怎么工作的?怎么保持的长连接?用的什么协议?

1, websock是一个基于tcp协议的长连接协议,它是全双工通信。

首先客户端发送http请求, 经过和服务端的3次握手后,建立链接。
然后服务端收到客户端的握手请求后,同样也采用HTTP协议发送回数据。 然后他们就可以直接通信

协程和线程的区别?

1,协程是一种比线程更加轻量级的存在。
2,一个线程就是执行一个子程序,子程序的调用是一个入口,一次返回,调用顺序明确。
而协程在子程序内部可以中断,然后去执行别的子程序,然后合适的时候返回继续执行。
3, 协程极高的执行效率,因为子程序的切换并不是线程切换,没有线程切换的开销,它完全由用户程
序控制。
4, 协程是不需要加锁, 因为只有一个线程,所以控制共享资源的时候只用判断状态就可以。

数字之和

有一个数字n,现在想把这个数字拆成两个非负整数a和b,使得a + b=n,对于每一种方案,我们定义
一个价值val=s(a) + s(b);
其中s(x)代表x的数位和,例如数字×= 1234,那么s(x)= 1+2+3+4 = 10。
现在想让你求可以选择的方案中val值最大的为多少?
例如输入 35 输出 17

//这个题的核心思路 : 把35拆分成两个数a, b , 使得 a + b = 35
//然后取出 a, b中每一个数字即可。 这里借用字符串要方便一些。

#include 
#include 
#include 
using namespace std;

int main()
{
	int T = 0;
	cin >> T;
	while (T--)
	{
		int n = 0;
		cin >> n;
		int value = 0;
		for (int i = 0; i <= n; i++)
		{
			for (int j = 0; j <= n; j++)
			{
				if (i + j == n)
				{
					string s1 = to_string(i);
					string s2 = to_string(j);
					int num = 0;
					for (int i = 0; i < s1.size(); i++)
					{
						num += s1[i] - '0';
					} 
					for (int i = 0; i < s2.size(); i++)
					{
						num += s2[i] - '0';
					} 
					value = max(value, num);
				}
			}
		} 
		cout << value << endl;
	} 

	return 0;
}

构造函数可以是虚函数吗?为什么?

不能, 因为虚函数表指针是在构造函数初始化列表阶段初始化的。

STL中的vector、list和map的底层实现?迭代器异常/失效

底层实现 : 数组,链表, 红黑树

什么是迭代器失效 :
1 迭代器指向了释放的空间 (野指针)
2,迭代器的意义变了 (例如在下标0位置插入1, 迭代器之前指向的是元素变成了1)

vector的插入删除操作 : 会导致当前和以后位置的迭代器是失效 (因为是需要罗董元素的)
list的插入删除操作 : 会导致当前位置的迭代器失效 (因为是链表)
map的插入删除操作 : 当前位置的迭代器失效

多线程怎么保证对临界资源的合理访问

可以通过加互斥锁,信号量,条件变量让多线程进行同步访问临界资源, 实质上是让并行运行的线程变成串行。

锁机制可以怎么优化?协程知道吗?

1, 减少锁持有时间,它有助于降低锁冲突的可能,提高系统的并发能力。
2, 减少锁的粒度, 实质上就是减少加锁的范围,这样也有助于降低锁冲突。
3, 用读写分离锁来替代独占锁, 在读多写少的情况下。

协程是比线程更加轻量化的存在。
一个线程就是一段子程序的执行,一个入口, 一个返回值。
而协程可以在执行一个子程序的时候,切换去执行另一个子程序,在合适的时候再切换回来。
协程间的切换不同于线程间的切换, 不需要将从CPU剥离下来,也就是没有线程切换的开销,而且它完
全由用户程序控制。
另外的话, 协程不需要加锁,因为只有一个线程,在访问共享资源的时候就比较简单

select和epoll的区别

1, 每次调用select的时候,都需要手动设置fd_set集合,意味着每次调用都需要从用户向内核拷贝大量数
据,而 epoll只需要在合适的时候通过epoll_ctr添加fd即可。
2,由于fd_set是一个位图结构,select关心的fd有限制, epoll无上限。
3,select中的内核检测fd就绪的时候是通过轮询遍历的方式,O(N),而epoll的底层是通过就绪队列
直接获取的O(1)。
4,select上的每一个fd没有分开监视的事件和发生的事件, 而epoll做到了参数分离

对于poll呢? 在select的基础上进行了优化 : 1 fd上的输入输出参数分离 2 文件描述符无上限

linux命令常用的有哪些?查看cpu和内存使用的命令?

ll, ls, mkdir, cp, mv, cd 。
top : 查看cpu
free: 查看内存使用
df: 产看磁盘分区可以使用的磁盘空间
du : 产看每个文件和目录的使用空间

time_wait状态什么时候会出现?一直出现这个状态会有什么不好的影响,怎么解决?

出现在主动断开tcp链接的第三次挥手中。
当客户端的某一些用户不活跃的时候, 服务端就会主动断开连接 :
服务端就有可能处于这个状态,会导致由于没有完全断开链接,而每一个链接就会占用一个通信5元组
(源IP, 目的IP, 目的端口, 源端口,协议)。 而服务端的ip和端口又是固定的,如果这个时候有客户端来链接的ip和端口与time_wait占用的链接重复, 就会出现问题。

如何解决 :通过函数 setsockopt() , 允许创建多个fd, 他们的ip不同, 但是共享一个相同的端口号

说说你做过的项目中最大的两个技术难点吧,最后怎么解决的?

我记得第一个技术难点就是在下载好的一个html文档里面,它的内容变成了一个string,既有大写也有
小写。 如何查找出与关键字相邻的前50个字符和后50个字符拼接,关键字又是全部小写的,我们是不需
要区分大小写,而string的find函数是区分大小写的。如何编写精简和高效的代码。 所以这里借助了标
准命名空间std::searcher函数加以利用lambda表达式来解决。

第二个难点就是之前运行起来很慢很卡,原因是在建立正排和倒排索引的时候,我每次都是拷贝一份结构体
DocInfo,然后那一份存在的结构体出作用域销毁,后来引入了std::move()函数,它可以将结构体的资
源窃取过来不需要重新拷贝。

你可能感兴趣的:(C++面经,c++)