20180815头条三面-How_2_Play_Life
Posted perfy576
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了20180815头条三面-How_2_Play_Life相关的知识,希望对你有一定的参考价值。
一面
1 找一个无序数组的中位数
老题,方法有:
- 先排序再定位
- 最大堆和最小堆配合
- 变体的快排
代码:
#include <map>
#include <vector>
#include <cmath>
#include <algorithm>
#include <stdio.h>
#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;
// 1 先排序,后取中位数
template <typename T>
T solve_by_sort(vector<T> src)
{
sort(src.begin(), src.end());
size_t len = src.size();
if (len & 0x01)
{
return src[len / 2 + 1];
}
else
{
return (src[len / 2 - 1] + src[len / 2]) / 2;
}
}
// 利用堆排序,如果是偶数,那么需要维持两个堆
// 或是如果是偶数,维持一个大根堆,大小为 len/2+1 ,
// 取出一个后,再建堆一次.貌似这样比较快
template <typename T>
T solve_by_heap(vector<T> src)
{
size_t len = src.size();
if (len & 0x01)
{
vector<T> tmp;
for (size_t i = 0; i < len; i++)
{
if (tmp.size() != len / 2 + 1)
{
tmp.push_back(src[i]);
}
else
{
cout << tmp[0] << endl;
// 大根堆留小的那个 堆顶是最大的
tmp[0] = min(tmp[0], src[i]);
}
// 大根堆
make_heap(tmp.begin(), tmp.end(), [](T v1, T v2) {
return v2 > v1;
});
}
return tmp[0];
}
else
{
vector<T> min_heap;
vector<T> max_heap;
for (size_t i = 0; i < len; i++)
{
if (min_heap.size() != len / 2)
{
min_heap.push_back(src[i]);
}
else
{
if (min_heap[0] < src[i])
{
max_heap.push_back(min_heap[0]);
min_heap[0] = src[i];
}
else
{
max_heap.push_back(src[i]);
}
}
make_heap(min_heap.begin(), min_heap.end(), [](T v1, T v2) {
return v1 > v2;
});
make_heap(max_heap.begin(), max_heap.end(), [](T v1, T v2) {
return v2 > v1;
});
}
cout << endl;
return (min_heap[0] + max_heap[0]) / 2;
}
}
// 3 快排的变体
// 主要是在拿到 partion 的返回值以后,只排序靠近k的位置
// 当partion 返回的下标是k的时候,那么就是第k个了
template <typename T>
T solve_by_qsort_aux_partion(T start, T end)
{
if (start > end)
{
return start;
}
T l = start;
T r = start;
while (r != end - 1)
{
if (*r < *(end - 1))
{
iter_swap(r, l);
l++;
r++;
}
else
{
r++;
}
}
iter_swap(end - 1, l);
return l;
}
template <typename T>
T qsort(T start, T end)
{
if (start != end)
{
T part = solve_by_qsort_aux_partion(start, end);
qsort(start, part);
qsort(part + 1, end);
}
}
template <typename T>
T solve_by_qsort_aux(T start, T end, T flag, int k)
{
if (start != end)
{
T part = solve_by_qsort_aux_partion(start, end);
// 主要是这一部分,向第k个判断
if (part - flag != k)
{
if (part - flag > k)
{
solve_by_qsort_aux(start, part, flag, k);
}
else
{
solve_by_qsort_aux(part + 1, end, flag, k);
}
}
else
{
return part;
}
}
}
template <typename T>
T solve_by_qsort(vector<T> src)
{
size_t len = src.size();
if (len & 0x01)
{
return *solve_by_qsort_aux(src.begin(), src.end(), src.begin(), len / 2 + 1);
}
else
{
T tmp1=(*solve_by_qsort_aux(src.begin(), src.end(), src.begin(), len / 2));
T tmp2=(*solve_by_qsort_aux(src.begin(), src.end(), src.begin(), len / 2-1));
return (tmp1+tmp2)/2;
}
}
int main()
{
vector<double> src = {5, 3, 2, 1, 4, 6};
cout << "solve_by_heap: " << solve_by_heap(src) << endl;
cout << "solve_by_sort: " << solve_by_sort(src) << endl;
qsort(src.begin(), src.end());
for (auto t : src)
{
cout << t << " ";
}
cout << endl;
cout << "solve_by_sort: " << solve_by_qsort(src) << endl;
}
因为没有改变double的值,因此,可以直接判断
建堆相关的函数:
make_heap
建堆,最后是二叉堆:接受两个迭代器,对迭代器之间的进行排序[)
区间,第三个参数是compare
函数[](T v1,T v2){return v1>v2}
,v1>v2
是降序,v2>v1
是升序sort_heap
堆排序,最后是排序结果:同上is_heap
判断是否是一个二叉堆:同上pop_heap
:进行排序,每次排一个,也就是说,将堆顶的元素,放入尾部,每次一个.
类priority_queue 使用了二叉堆.默认最大堆.
priority_queue<int,vector<int>,std::greater<int>> pq;
最小堆
priority_queue<int,vector<int>,std::less<int>> pq;
最大堆(默认)
快排编写时候,最主要的是判断,边界.
2 无序数组第k大的一个数
和上一个题是同一个题
3 快排和堆的复杂度
快排最好的情况是,每次正好中分,复杂度为O(nlogn)。最差情况,复杂度为O(n^2),退化成冒泡排序
初始化建堆的时间复杂度为O(n),排序重建堆的时间复杂度为nlog(n)
4 操作系统了解么Linux和windows?????
宏内核和微内核,开源闭源
5 Linux的磁盘管理
- df:列出文件系统的整体磁盘使用量
- du:检查磁盘空间使用量
- fdisk:用于磁盘分区
- mkfs: 磁盘格式化
df命令参数功能:检查文件系统的磁盘空间占用情况。可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信息。 df命令是显示文件系统,磁盘级别上.无论在哪个目录下运行,基本都是下面的信息(window子系统)
du命令是对文件和目录磁盘使用的空间的查看 ,是文件夹级别的.
一般加上--max-depth=数字
表示递归多少层,否则,du命令会在当前目录下每个子文件夹都展示出来
6 Linux进程通信方式
- 管道(pipe),流管道(s_pipe)和有名管道(FIFO)
- 信号(signal)
- 消息队列
- 共享内存
- 信号量
- 套接字(socket)
7 Linux的共享内存使用以及实现
int shmget( key_t shmkey , int shmsiz , int flag );
void *shmat( int shmid , char *shmaddr , int shmflag );
int shmctl( int shmid , int cmd , struct shmid_ds *buf );
int shmdt( char *shmaddr );
shmget()
key_t shmkey 是这块共享内存的标识符。如果是父子关系的进程间通信的话,这个标识符用IPC_PRIVATE来代替。但是刚才我们的两个进程没有任何关系,所以就用ftok()算出来一个标识符使用了。 int shmsiz 是这块内存的大小. int flag 是这块内存的模式(mode)以及权限标识。 模式可取如下值: 新建:IPC_CREAT 使用已开辟的内存:IPC_ALLOC 如果标识符以存在,则返回错误值:IPC_EXCL 然后将“模式” 和“权限标识”进行“或”运算,做为第三个参数。 如: IPC_CREAT | IPC_EXCL | 0666 这个函数成功时返回共享内存的ID,失败时返回-1。
shmat()
是用来允许本进程访问一块共享内存的函数。 int shmid是那块共享内存的ID。 char *shmaddr是共享内存的起始地址 int shmflag是本进程对该内存的操作模式。如果是SHM_RDONLY的话,就是只读模式。其它的是读写模式 成功时,这个函数返回共享内存的起始地址。失败时返回-1。
int shmctl( int shmid , int cmd , struct?shmid_ds *buf );
int shmid是共享内存的ID。 int cmd是控制命令,可取值如下: IPC_STAT 得到共享内存的状态 IPC_SET 改变共享内存的状态 IPC_RMID 删除共享内存 struct shmid_ds *buf是一个结构体指针。IPC_STAT的时候,取得的状态放在这个结构体中。如果要改变共享内存的状态,用这个结构体指定。 返回值:?成功:0 失败:-1
8 TCP的三次握手和四次挥手
9 docker 原理
10 cgroup在linux的具体实现
二面
1 mysql
索引的实现,innodb的索引,b+树索引是怎么实现的,为什么用b+树做索引节点,一个节点存了多少数据,怎么规定大小,与磁盘页对应
2 ?MySQL的事务隔离级别,分别解决什么问题。
3 Redis
如果Redis有1亿个key,使用keys命令是否会影响线上服务,我说会,因为是单线程模型,可以部署多个节点
持久化方式
Redis的list是怎么实现
sortedset怎么实现
4 skiplist的数据结构
不知道,AVL看的都累
5 消息队列
kafka,zookeep
6 一个有向图用邻接矩阵表示,并且是有权图,现在问怎么判断图中有没有环
7 一个二叉树,找到二叉树中最长的一条路径。
三面
8 操作系统的进程通信方式,僵尸进程和孤儿进程是什么,如何避免僵尸进程,我说让父进程显示通知,那父进程怎么知道子进程结束了,答不会
9 计算机网络TCP和UDP有什么区别
为什么迅雷下载是基于UDP的,我说FTP是基于TCP,而迅雷是p2p不需要TCP那么可靠的传输保证。
10 操作系统的死锁必要条件,如何避免死锁。
产生死锁的四个必要条件:
- 互斥条件:一个资源每次只能被一个进程使用。
- ?占有且等待:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不可强行占有:进程已获得的资源,在末使用完之前,不能强行剥夺
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。
11 LRU的缓存
最近未使用
大致的思路是这样的:
- unordered_map用来在O(1)内取节点
- 双向链表,用来维持要删除谁
两个数据结构的节点都指向LruNode.
template <class K, class T>
struct LruNode
{
LruNode(K k, T t)
: key(k), data(t),
prev(nullptr), next(nullptr)
{
}
K key;
T data;
LruNode *prev, *next;
};
template <typename K,typename T>
class Lru
{
public:
Lru(size_t max_size = 10)
: m_max(max_size),
root(nullptr),
end(nullptr)
{
}
T get(K k)
{
if (m_hash.find(k) != m_hash.end())
{
LruNode<K,T>* target = m_hash[k];
if (target != end)
{
target->next->prev = target->prev;
}
else if (target != root)
{
end = target->prev;
target->prev->next = nullptr;
}
if (target != root)
{
target->prev->next = target->next;
target->next = root;
target->prev = nullptr;
root = target;
}
return target->data;
}
else
{
return T();
}
}
void push(K k, T t)
{
LruNode<K,T> *target = new LruNode<K,T>(k, t);
if (root != nullptr)
{
target->next = root;
root->prev=target;
root = target;
}
else
{
root = target;
end = target;
}
m_hash[k] = target;
if (m_hash.size() > m_max)
{
LruNode<K,T> *trash = end;
end = end->prev;
end->next=nullptr;
delete trash;
}
}
size_t size()
{
return m_hash.size();
}
private:
size_t m_max;
LruNode<K,T> *root;
LruNode<K,T> *end;
unordered_map<K, LruNode<K,T> *> m_hash;
};
以上是关于20180815头条三面-How_2_Play_Life的主要内容,如果未能解决你的问题,请参考以下文章