作者:兵长一米六
链接:https://www.nowcoder.com/discuss/232268?type=all&order=time&pos=&page=1
来源:牛客网
第一次开发类面试的经历,控制不住的紧张啊,形式是视频面试,全程1h
1 //给了玩家列表,随机选出N个玩家 2 #include3 #include 4 #include 5 #include <set> 6 #include 7 using namespace std; 8 9 //会出现重复,所以使用set 10 set<int> getRandomPlayers(const vector<int> &players, int n) 11 { 12 set<int> res; 13 srand((unsigned int)time(NULL)); 14 while (res.size() < n) 15 { 16 int m = rand() % players.size(); 17 res.insert(players[m]); //C++17 18 } 19 return res; 20 } 21 22 int main() 23 { 24 vector<int> test = {1, 5, 999, 89076, 321, 23876, 12345, 2, 4, 654, 567, 1001}; 25 auto set = getRandomPlayers(test, 4); 26 cout << "选出的用户: "; 27 for (int i : vec) 28 cout << i << " "; 29 30 return 0; 31 }
C++的特性:
1.封装:从食物中抽取共性,抽象成为类,将类的属性和对于属性的操作方法组合成为一个类,即是封装;
2.继承:通过基类派生子类的方式,可以实现代码的复用;
3.多态:静态多态和动态多态
静态多态:函数重载(函数重载需要注意二义性)和模板。模板又分为函数模板和类模板,是一种泛型编程方式,
template
ret type fucname(T t1, T t2...)
{...}
T相当于再占位,等待具体的类型来替换他(实例化它)。一般所见到的容器和一些泛型算法都是模板,STL中大量使用了模板。
类的默认生成成员
构造、析构,拷贝构造和拷贝赋值函数。
拷贝构造干了什么?
使用一个已存在的对象去实例化一个对象,比如:
1 class A{ 2 public : 3 A(); 4 ~A(); 5 A* A(const A&a){ 6 m = a.m; 7 } 8 private: 9 int m; 10 }
还涉及到深拷贝和浅拷贝的问题。
结合内存对齐的类大小问题
模板实例化
显示实例化和隐式实例化
特化和偏特化
模板有部分实例化和完全实例化两种类型,在C++primer中后面章节中有介绍。
实例化即是将模板中的类型集体化,这里说的应该是特化,那么就是把所有的模板类型都具体化,可以实例化为具体的int/double...类型或者实例化为容器类型都可以,模板实例化其实是编译器的工作,如果想要固定部分参数或者返回值的类型,可以使用实例化,但完全实例化也就失去了模板的意义。
操作系统:虚拟内存
虚拟内存和物理内存对应,是OS中概念。物理内存是不变的,但我们可以通过在运行程序时,只将一部分数据装入内存中,在用到其他程序或者数据时,再将它们从外存/辅储中置换进来。更加具体一点:当CPU需要访问某页数据或者程序时,先从该数据的逻辑地址中拿到逻辑的组号和组内的逻辑地址,先判断该组是否在内存中,如果在,直接去访问,通过地址转换表拿到对应的物理组号,然后根据组内的逻辑地址访问数据。如果找不到该组,那么就需要从从辅存中将该页置换进入内存中,如果内存中有空余页,那么直接置换,如果没有,那么遵循一定规则将某些也置换出内存。具体的置换方法:先进先出、最近最少使用、最佳算法(预估最长时间才会使用的页调出内存,是一种理想的算法)。
动态链接和静态链接
是程序整个编译过程中的一盒环节,链接的两种不同方式。程序从编辑,预编译,编译得到汇编代码,然后经过汇编得到二进制文件,再经过链接得到可执行文件。而静态连接是将用到的函数和库直接装入可执行文件中,动态链接不是,他和可执行文件是分离的,再运行时用到才去该文件中寻找调用。
二者的优缺点:
1. 静态链接使得可执行文件比较臃肿,而动态链接的可以节省存储空间;
2. 静态链接会存在重复装入的问题,如果多次调用某函数,那么就会多次装入该函数,所以需要使用ifndef之流来改善,而动态链接不需要(运行时动态调用);
3. 扩展和更新:显然动态链接的扩展性要好于静态。只要更换动态链接库即可,然只要发生更改,静态链接库还需要重新编译源程序。
4. 在Windows中分别是*.lib,*.dll;而在Linuxz中是lib*.a和*.so
计算机网络:TCP、UDP区别、所在层(传输层),ping用哪个
1.有无连接;tcp有连接,udp无连接
2.是否可靠;tcp可靠,udp不可靠
3.那种协议;tcp流式协议,udp数据报式协议
4.发送速率:就拿单次数据请求来说,tcp需要:2*RTT+SPT,udp只需要RTT+SPT。
5.发端和收端的关系:tcp发端发送次数和收端接受次数没有数量关系,udp发送一次就必须接收,且如果接收缓冲区小于数据报的长度,那么会发生截断,多余数据丢失;tcp不会,双方都维护有拥塞窗口,会动态的进行流量控制。
6.适用范围:广播多播必须使用udp,大量数据一般使用tcp,如文件传输;一般的音视频传输也使用udp。
ping使用ICMP协议
数据结构算法:红黑树
红黑树是一种平衡二叉树,当然他不像AVL树那样,要求左右子树深度之差不超过1,而是一种折中方案。
他有以下特性:
节点有颜色,且非黑即红;
根节点为黑色
叶子节点为黑色
红色节点子节点必须为黑;
从根节点到叶子节点路径上的黑色节点个数必须要相等;
由于上面的特性,使得红黑树较为平衡log(n),他没有AVL树那样平衡,但是可以通过较少的旋转和变色来维持平衡,总体性能上要好于AVL树,所以STL中的map/set等都使用了红黑树。
查找插入和删除最坏都为O(log(n))
排序算法
一般的有冒泡、插入、选择、快排、堆排序、归并排序
稳定的排序算法有插入、冒泡和归并排序;
最快的算法一般都是:O(nlogn),快排、归并排序、堆排序;其他的平均时间复杂度都是O(n2);
3min写个快排(自己加的)
1 void quickSort(vector<int> &nums, int l, int r) 2 { 3 if (l >= r) 4 return; 5 int i = l, j = r + 1; 6 int key = nums[l]; 7 while (true) 8 { 9 while (nums[++i] < key) 10 { 11 if (i == r) 12 break; 13 } 14 while (nums[--j] > key) 15 { 16 if (j == l) 17 break; 18 } 19 if (i >= j) 20 break; 21 int tmp = nums[i]; 22 nums[i] = nums[j]; 23 nums[j] = tmp; 24 } 25 int tmp = nums[l]; 26 nums[l] = nums[j]; 27 nums[j] = tmp; 28 quickSort(nums, l, j - 1); 29 quickSort(nums, j + 1, r); 30 }
拓扑排序?
(没见过)
深度搜索、广度搜索
编程题:
给了一个整数,得到一个逆序的整数
1 //整数逆序1,使用to_string 2 long long reverseInteger(int n) 3 { 4 long long res = 0; 5 string str = to_string(n); 6 //12345->54321 7 for (int i = str.length() - 1; i >= 0; i--) 8 { 9 res = res * 10 + (str[i] - '0'); 10 } 11 return res; 12 }
1 //整数逆序1,不使用其他函数,但需要辅助队列 2 long long reverseInteger(int n, int flag) 3 { 4 long long res = 0; 5 //必须要一个辅助容器,stack就不错 6 queue<int> q; 7 while (n) 8 { 9 q.push(n % 10); 10 n /= 10; 11 } 12 while (!q.empty()) 13 { 14 res = res * 10 + q.front(); 15 q.pop(); 16 } 17 return res; 18 }
从左上到右下,找到和最小的路径(动态规划)
1 //使用极限电量来完成最短路径和(每一步都只能往右或者下走) 2 int getShorstLoad(vectorint>> &m) 3 { 4 int row = m.size(), col = m[0].size(); 5 vector int>> dp = m; 6 for (int i = 0; i < row; i++) 7 { 8 for (int j = 0; j < col; j++) 9 { 10 if (i == 0 && j == 0) 11 dp[i][j] = m[0][0]; 12 else if (i == 0) 13 dp[i][j] = m[i][j] + dp[i][j - 1]; 14 else if (j == 0) 15 dp[i][j] = m[i][j] + dp[i - 1][j]; 16 else 17 dp[i][j] = m[i][j] + min(dp[i - 1][j], dp[i][j - 1]); 18 } 19 } 20 return dp[row - 1][col - 1]; 21 }