赞
踩
x2 / a2+y2 / b2+z2 / c2=1。
当x2/a2+y2/b2+z2/c2<1时 则点(x,y,z)在内部
反转链表
删除导数第N个数
总体很简单,有两个特殊的需要注意,第一是只有一个数或者零个数,第二个是需要删除的是第一个数
if(!head || !head -> next) return NULL;//判断是否只有一个数或者零个数
ListNode* first = head;
ListNode* second = head;
for(int i = 0;i<n;i++) second = second->next;
if(!second) return head->next; //判断是否要删的是第一个数,因为你要是走完发现走到了尽头就说明倒数第N个数是开头,那么久直接返回head->next就行,用源代码会有bug
高精度加法
一个很妙的不用判断进位并且前面0的处理方法
while(n1>=0 || n2>=0 || jw){
int x = n1 >= 0 ? num1[n1] - '0' : 0;
int y = n2 >= 0 ? num2[n2] - '0' : 0;
n变成1
n如果是奇数就变成n-1或者n+1,如果是偶数就变成n/2
用动态规划
vector<int> dp;
dp[0] = 0;
dp[1] = 0;
for(int i = 2;i<n;i++){
if(i%2==0) dp[i] = dp[i/2] +1;
else dp[i] = min(dp[i-1],dp[i+1]) + 1;
}
return dp[n];
static
https://zhuanlan.zhihu.com/p/37439983
为什么需要虚继承
1、为了解决多继承时的命名冲突和冗余数据问题
C++ 提出了虚继承,使得在派⽣类中只保留⼀份间接基类的成员。其中多继承(Multiple Inheritance)是指从多个直接基类中产⽣派⽣类的能⼒,多继承的派⽣类继承了所有⽗类的成员。
2、虚继承的⽬的是让某个类做出声明,承诺愿意共享它的基类
数据库保护四种
安全性控制,完整性控制,并发性控制和数据恢复
stl底层实现
vector:数组
Dequeue(双端队列):二维数组
List:环状双向链表
set(集合):平衡的红黑树
multiset:红黑树
map:平衡二叉树
哈希表相关
哈希函数
避免冲突
一个是开放寻址法,一个是拉链法
指针常量和常量指针
指针常量就是指针本身是常量,换句话说,就是指针里面所存储的内容(内存地址)是常量,不能改变。但是,内存地址所对应的内容是可以通过指针改变的。
常量指针就是指向常量的指针,换句话说,就是指针指向的是常量,它指向的内容不能发生改变,不能通过指针来修改它指向的内容。但是,指针自身不是常量,它自身的值可以改变,从而指向另一个常量。
线程和进程
cpu分配时间片的最小单位是什么?
答:线程,进程是资源分配的最小单位,线程是运行调度的最小单位。
cpu分配时间片的算法
实现一个SolidWorks包括什么部分?技术栈是怎样?
c++与c的区别,面向对象体现在哪里
指针和引用区别
在C和C++中,指针一般指的是某块内存的地址,通过这个地址,我们可以寻址到这块内存;而引用是一个变量的别名,例如我们给小明起了个外号:明明,那我们说明明的时候,就是说小明。
指针可以为空,引用不能为空
如何解释函数指针
让函数数据化的东西,比如说可以优化很多的if-else语句,
多态底层实现
编译过程,是否生成dll,替换库行不行
如何捕捉未定义的内存错误
有哪些内存泄露,如何解决
常见错误:https://blog.csdn.net/Joker_N/article/details/102688822
如何解决:https://blog.csdn.net/daaikuaichuan/article/details/80874436
申请和释放不一致
由于 C++ 兼容 C,而 C 与 C++ 的内存申请和释放函数是不同的,因此在 C++ 程序中,就有两套动态内存管理函数。一条不变的规则就是采用 C 方式申请的内存就用 C 方式释放;用 C++ 方式申请的内存,用 C++ 方式释放。也就是用 malloc/alloc/realloc 方式申请的内存,用 free 释放;用 new 方式申请的内存用 delete 释放。在上述程序中,用 malloc 方式申请了内存却用 delete 来释放,虽然这在很多情况下不会有问题,但这绝对是潜在的问题。
申请和释放不匹配
申请了多少内存,在使用完成后就要释放多少。如果没有释放,或者少释放了就是内存泄露;多释放了也会产生问题。上述程序中,指针p和pt指向的是同一块内存,却被先后释放两次。
释放后仍然读写
本质上说,系统会在堆上维护一个动态内存链表,如果被释放,就意味着该块内存可以继续被分配给其他部分,如果内存被释放后再访问,就可能覆盖其他部分的信息,这是一种严重的错误,上述程序第16行中就在释放后仍然写这块内存。
对策
1.避免在堆上分配内存
既然只有堆上会发生内存泄露,那第一原则肯定是避免在堆上面进行内存分配,尽可能的使用栈上的内存,由编译器进行分配和回收,这样当然就不会有内存泄露了。
1、管道
2、消息队列
3、共享内存
4、信号量
5、Socket
进程内存划分
如上图,从低地址到高地址,一个程序由代码段、数据段、BSS段、堆、共享区、栈等组成。
**数据段:**存放程序中已初始化的全局变量和静态变量的一块内存区域。
**代码段:**存放程序执行代码的一块内存区域。只读,代码段的头部还会包含一些只读的常数变量。
BSS 段:存放程序中未初始化的全局变量和静态变量的一块内存区域。
可执行程序在运行时又会多出两个区域:堆区和栈区。
**堆区:**动态申请内存用。堆从低地址向高地址增长。
**栈区:**存储局部变量、函数参数值。栈从高地址向低地址增长。是一块连续的空间。
最后还有一个共享区,位于堆和栈之间。
三次握手四次握手过程,timewait作用
https://zhuanlan.zhihu.com/p/86426969
为什么握手要三次
弄清这个问题,我们需要先弄明白三次握手的目的是什么,能不能只用两次握手来达到同样的目的。
第一次握手:客户端发送网络包,服务端收到了。
这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
第二次握手:服务端发包,客户端收到了。
这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
第三次握手:客户端发包,服务端收到了。
这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。
因此,需要三次握手才能确认双方的接收与发送能力是否正常
为什么挥手要四次
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了”。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。
一个用户上网的过程
1.在浏览器的地址栏中输入URL。
2.浏览器检查缓存中的DNS记录,以找到URL对应的IP地址。
3.如果请求的URL不在缓存中,ISP的DNS服务器将发起DNS查询以查找托管URL的服务器的IP地址。
中间还有一段
第五步,回应报文经过封装,在网络中进行转发(利用各种路由协议如OSPF在网络中进行路由转发,利用ARP协议在二层设备上进行数据转发),最后发送到请求域名解析的主机。
主机分析数据包,知道IP地址后,写入DNS缓存表,浏览器接着给这个IP的服务器发送HTTP请求。
第六步,已经知道目标IP地址了,但是为了将消息传到服务器上要经过OSPF动态路由算法去进行路由转发,然后IP地址使用的是IP协议,整个发送过程中只涉及出发地和目的地2个IP地址,而ARP协议使用的是MAC地址,整个发送过程中涉及到每一个节点的MAC地址 。
4.浏览器发起与服务器的TCP连接。
5.浏览器向网络服务器发送HTTP请求。
6.服务器处理请求并发回响应。
7.服务器发出HTTP响应。
服务器响应包含你请求的网页以及状态码、压缩类型(Content-Encoding)、如何缓存页面(Cache-Control)、要设置的任何cookie。隐私信息等。
8.浏览器显示HTML内容(对应HTML响应,这是最常见的)。
快慢指针
将一个栈当作输入栈,用于压入 \texttt{push}push 传入的数据;另一个栈当作输出栈,用于 }pop 和 peek 操作。
每次 pop 或 peek 时,若输出栈为空则将输入栈的全部数据依次弹出并压入输出栈,这样输出栈从栈顶往栈底的顺序就是队列从队首往队尾的顺序。
https://zhuanlan.zhihu.com/p/431714886
vector容量上限,扩容策略
动态扩容,每次都增加到当前的2倍,然后如果超过max
map一一对应可以是类吗,类的话怎么实现一一对应
可以,因为map的底层实现是红黑树,只要保证你定义的类有比较符号即可
多态
双端队列
元素可以从队头出队和入队,也可以从队尾出队和入队
手写二分查找
int Binary(vector<int> ary, int target){
int n = ary.size();
if(n==0) return -1;
int left = 0, right = n - 1;
int mid;
while(left<=right){
mid = (left + right) / 2;
int m = ary[mid];
if(m==target) return mid;
else if(m<target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
手写快排
#include<iostream> using namespace std; int n,a[1000001]; void qsort(int l,int r)//应用二分思想 { int mid=a[(l+r)/2];//中间数 int i=l,j=r; do{ while(a[i]<mid) i++;//查找左半部分比中间数大的数 while(a[j]>mid) j--;//查找右半部分比中间数小的数 if(i<=j)//如果有一组不满足排序条件(左小右大)的数 { swap(a[i],a[j]);//交换 i++; j--; } }while(i<=j);//这里注意要有= if(l<j) qsort(l,j);//递归搜索左半部分 if(i<r) qsort(i,r);//递归搜索右半部分 } int main() { cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; qsort(1,n); for(int i=1;i<=n;i++) cout<<a[i]<<" "; }
引用和指针(才知道引用直接传名字就可以,然后不用传指针)
进程间通信,(注意和进程中通信区别,并且问你有没有实践过)
网络编程
三次握手
数据库,非关系型和关系型,MongoDB和MySQL有啥区别,为啥选MongoDB
一面
寻找第k大
1.找钱的方案数变种,拿手机,每次可以拿1、2、3、4,问有几种拿法,爬楼梯变种
作者:拼子 链接:https://www.nowcoder.com/discuss/856152?type=all&order=recall&pos=&page=1&ncTraceId=&channel=-1&source_id=search_all_nctrack&gio_id=DCFD5C44A0863546D8B2F332A84B6BCB-1646712477134 来源:牛客网 public static void main(String[] args) { Scanner in = new Scanner(System.in); while (in.hasNext()) { int n = in.nextInt(); int[] dp = new int[20000]; dp[0] = 1; dp[1] = 1; dp[2] = 2; dp[3] = 4; dp[4] = 8; if (n < 5) { System.out.println(dp[n]); } else { for (int i = 5; i <= n; i++) { dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3] + dp[i - 4]; } System.out.println(dp[n]); } } }
2.滑动窗口,LeetCode原题:https://leetcode-cn.com/problems/frequency-of-the-most-frequent-element/
3.多重背包+最小值,没写出来
作者:衣冠胜雪 链接:https://www.nowcoder.com/discuss/856152?type=all&order=recall&pos=&page=1&ncTraceId=&channel=-1&source_id=search_all_nctrack&gio_id=DCFD5C44A0863546D8B2F332A84B6BCB-1646712477134 来源:牛客网 public static int minCost(int rooms, int staffNum, int[] count, int[] roomCapacity, int[] cost) { //rooms房间种类,staffNum总员工数,count 是每种房间的数量,roomCapacity是每种房间的承载人数,cost是每种房间的花费 //dp[i][j]表示前i种房间住j个staff的最小花费 int[][] dp = new int[rooms][staffNum+1]; for (int i = 1; i <= staffNum; i++) { // 设置只住第一种旅馆的花费 int roomNum = Math.min(i%roomCapacity[0]==0?i/roomCapacity[0]:i/roomCapacity[0]+1,count[0]); if(roomNum*roomCapacity[0]>=i) { dp[0][i] = roomNum * cost[0]; }else{ dp[0][i]=Integer.MAX_VALUE/2;//超出第1种房间承受范围的员工数设为最大值的一半,防止后面加法越界 } } for (int i = 1; i < rooms; i++) { for (int j = 1; j <= staffNum; j++) { int prevMin = dp[i-1][j]; //求出0~i-1种房间中住j个人的最小花费 int curMin = Integer.MAX_VALUE;//设置当前花费为最大 for (int k = 1; k <= count[i]; k++) {//遍历当前房间承受最大范围,求出该范围内花费最小值 if(j<k*roomCapacity[i]){ break; } curMin = Math.min(curMin,dp[i-1][j-k*roomCapacity[i]]+k*cost[i]); } dp[i][j]=Math.min(prevMin,curMin);//和i-1种房间最小值比较,较小的则为i种房间j个员工的最小值 } } return dp[rooms-1][staffNum]; }
为什么选择客户端
对游戏引擎了解吗?
玩过什么游戏
说一下多态
说一下虚函数表保存在哪里
当生成类对象的时候,编译器会自动的将类对象的前四个字节设置为虚表的地址,而这四个字节就可以看作是一个指向虚函数表的指针。虚函数表可以看做一个函数指针数组。
构造函数初始化链表和直接在构造函数里面初始化有什么区别?
一句话,在进入派生类的构造函数内的时候,基类的部分已经构造完成了,你没有使用成员初始化列表初始化基类,因此基类采用的是基类自己默认的构造函数初始化的,然后进入构造函数后,你又使用基类的构造函数构造一次,说明基类部分构造了两次,肯定报错。
在构造函数初始化赋值效率低
常数据成员的初始化必须在初始化列表里完成
设计模式了解吗?平时用过吗?
1.单一职责。每个类只实现一个功能,而不要融合太多功能在一个类里
2.开放封闭原则。对增加开放,对修改关闭(增加功能可以)
3.依赖倒转原则。依赖于抽象(接口或父类),而不依赖于实现(子类)
4.迪米特法则(模块A只接触和自己有直接关系的模块B,如果模块B和模块C有直接关系, 而 模块A和模块C,没有,则A调用C ,要通过B,而不是直接调用)
危险的事情:
1.复制代码是危险的。如果有两段相同的代码,几乎可以说一定是有问题的,因为每次改动,要维护两段代码
2.尽量减少IO操作,如操作数据库,网络发送,甚至printf ,这些操作比直接操作内存,慢很多倍、
3.修改Bug时,一定要从最简单的基本的地方开始检查,不要检查到最底层没问题,发现是传入的某个参数是错的。先不要怀疑系统的部分。
4.设计架构,同时了解细节
5.有些Bug,调起来可能费时费力,甚至花个二三天,其实当时写的时候,只要稍微注意,就可以轻松避免。避免Bug的代价与找出并修改Bug的代价,实在是差太多了。
6.把一段长代码,分成很多小函数,便于维护,连自己都不愿看,不愿改的代码,百分百有问题。
7.写程序时,先把流程搞清楚。把各个流程用的函数写清楚,函数可以留空,这样编程就变成了填空题。
做新功能时,把数据结构的设计,放在较重要的位置
数据结构知道什么?平时项目用过什么?(说了一个多叉树,然后说了一下和红黑树和哈希表的优劣对比)
构建堆的算法。时间复杂度是多少
如何不排序找中位数,时间复杂度是多少?
主要根据你的简历问了很多,所以要细心准备简历上每一个东西,包括但不限于:
进程间通信
signal kill
程序内存结构
static的作用
单例模式怎么实现?构造函数怎么写?
作者:Zopen 链接:https://zhuanlan.zhihu.com/p/62014096 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 #include <iostream> #include <thread> #include <mutex> using namespace std; std::once_flag flag; class Singleton { public: static Singleton& getInstance() { std::call_once(flag, []() {instance_.reset(new Singleton()); }); return *instance_; } private: static std::unique_ptr<Singleton> instance_; private: Singleton() = default; Singleton(const Singleton& other) = delete; Singleton& operator=(const Singleton&) = delete; }; std::unique_ptr<Singleton> Singleton::instance_; void do_onceflag() { Singleton& s = Singleton::getInstance(); cout << &s << endl; } int main() { std::thread t1(do_onceflag); std::thread t2(do_onceflag); t1.join(); t2.join(); return 0; }
寻找共同最近祖先
多态了解吗?
知道右值吗?
可见左右值的概念很清晰,有地址的变量就是左值,没有地址的字面值、临时值就是右值。
右值就是拷贝了之后删了原来的,左值就是直接深拷贝?
大象的例子可以改成:大象本来放到A冰箱的, 后来想移动到B冰箱,移动语义的做法就是把冰箱上的A标志改成B标志, 这样就相当于放到了B冰箱,也不用重新去打造一个新的B冰箱了
最大连续子序列和
问了项目,什么比较难,问了一下做的微信小程序,要怎么改进?
快排复杂度,比快排好的有什么
B树和B+树对比,应用场景?
平衡二叉树定义?插入了怎么维护性质
动态规划是什么?举个例子
深拷贝浅拷贝区别?有什么要注意的地方
虚函数有什么用
C++11特性知道吗?智能指针知道吗?
vector和list的扩容
任务调度算法?猜一下windows是用了什么
如何避免死锁?
如何实现同步?
HTTP和TCP的区别
HTTPS和HTTP的区别
get和pos区别
外件和组件
数据库相关:事物知道吗?索引知道吗
笔试题三道:
1.设定如下的对应关系( A=0,B=1,C=2,…,Z=25,AA=26,AB=27,…,AAA=xxx,… ),编写一个转换函数,根据上面的规则把一个字符串转换为数字
int StrToInt( const char * str ){
int length = str.size();
int sum = 0;
for(int i = 0;i<length);i++){
int temp = str[i] - ‘A’;
if (temp>=26 || temp<0){
return -1;
}
sum = 26 * sum + temp;
}
return sum;
}
2.从有序链表中去除重复的元素
(1, 1, 3, 3, 3, 5, 5, 5, 9, 9, 9, 9) -> (1, 3, 5, 9).
struct LinkNode {
int val;
struct LinkNode * next;
};
void remove( LinkNode * head ){
if (head == nullptr) return head;
LinkNode* L = head;
while(L->next){
if(L->val == l->next->val){
L->next = L->next->next;
}
}
return head;
}
\3. 费南德的金币游戏:费南德和你抢到20个银币和一个金币,你们的分赃规则:俩人轮流拿,每次至少拿一个最多不能超过四个(可以等于四个),金币和银币不能混合拿,金币最后拿!如果由你先拿,怎么才可以拿到那个金币?(写拿的方法,不是写代码)
拿四个稳赢,接下来他拿i个,你就拿5-i,这样一定会剩一个给他拿,这样我们就赢了
= str.size();
int sum = 0;
for(int i = 0;i<length);i++){
int temp = str[i] - ‘A’;
if (temp>=26 || temp<0){
return -1;
}
sum = 26 * sum + temp;
}
return sum;
}
2.从有序链表中去除重复的元素
(1, 1, 3, 3, 3, 5, 5, 5, 9, 9, 9, 9) -> (1, 3, 5, 9).
struct LinkNode {
int val;
struct LinkNode * next;
};
void remove( LinkNode * head ){
if (head == nullptr) return head;
LinkNode* L = head;
while(L->next){
if(L->val == l->next->val){
L->next = L->next->next;
}
}
return head;
}
\3. 费南德的金币游戏:费南德和你抢到20个银币和一个金币,你们的分赃规则:俩人轮流拿,每次至少拿一个最多不能超过四个(可以等于四个),金币和银币不能混合拿,金币最后拿!如果由你先拿,怎么才可以拿到那个金币?(写拿的方法,不是写代码)
拿四个稳赢,接下来他拿i个,你就拿5-i,这样一定会剩一个给他拿,这样我们就赢了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。