码迷,mamicode.com
首页 > 其他好文 > 详细

20180815头条三面-How_2_Play_Life

时间:2018-08-16 13:33:28      阅读:180      评论:0      收藏:0      [点我收藏+]

标签:b+树   oid   shmdt   sort   out   cto   --   模式   redis   

链接

一面

1 找一个无序数组的中位数

老题,方法有:

  1. 先排序再定位
  2. 最大堆和最小堆配合
  3. 变体的快排

代码:

#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的值,因此,可以直接判断

建堆相关的函数:

  1. make_heap建堆,最后是二叉堆:接受两个迭代器,对迭代器之间的进行排序[)区间,第三个参数是compare函数

    [](T v1,T v2){return v1>v2},v1>v2是降序,v2>v1是升序

  2. sort_heap堆排序,最后是排序结果:同上

  3. is_heap判断是否是一个二叉堆:同上

  4. 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进程通信方式

  1. 管道(pipe),流管道(s_pipe)和有名管道(FIFO)
  2. 信号(signal)
  3. 消息队列
  4. 共享内存
  5. 信号量
  6. 套接字(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 操作系统的死锁必要条件,如何避免死锁。

产生死锁的四个必要条件:

  1. 互斥条件:一个资源每次只能被一个进程使用。
  2. ?占有且等待:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  3. 不可强行占有:进程已获得的资源,在末使用完之前,不能强行剥夺
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。

11 LRU的缓存

最近未使用

大致的思路是这样的:

  1. unordered_map用来在O(1)内取节点
  2. 双向链表,用来维持要删除谁

两个数据结构的节点都指向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

标签:b+树   oid   shmdt   sort   out   cto   --   模式   redis   

原文地址:https://www.cnblogs.com/perfy576/p/9486350.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!