腾讯日常实习(劳务实习)一面(超详细!!)

6.28–14:30一面(耗时一个半小时)(记录第一次面试)

面试部门:微信搜一搜

目录

  • 6.28--14:30一面(耗时一个半小时)(记录第一次面试)
    • 面试部门:微信搜一搜
    • 两道算法题
    • c++基础知识
    • 操作系统
    • 计算机网络
    • STL
    • 算法(补)
    • 结尾

两道算法题

  1. 翻转列表

    //题目,实现下面这个函数
    struct LinkNode{
    	int value;
    	LinkNode* next;
    }
    void reverse(LinkNode* head);
    

    题目不难,但是自己出现了很多小毛病,先放我当时写的代码

    #include 
    using namespece std;
    struct LinkNode{
        int value;
        LinkNode* next;
    }
    LinkNode* reverse(LinkNode* head){
        if(!head) return head;
        LinkNode* t = head;
        head = head->next;
        while(head){
            LinkNode *l = head->next;	//这里判定也有问题,面试没问,需要加上head->next为null的情况
            head->next = t;
            t = head;
            head = l;
        }
        return t;
    }
    int main(){
        LinkNode *l1, *l2, *l3;
        l1->value = 1;
        l2->value = 2;
        l3->value = 3;
        l1->next = l2;
        l2->next = l3;
        l3->next = nullptr;
        l1 = reverse(l1);
        while(l1){
            cout << l1->value << endl;
            l1 = l1->next;
        }
        return 0;
    }
    

    这里出现了好几个比较弱智的问题,一个一个说:

    • 我写的函数和题目给的函数不一样!!题目里的函数返回是void,我写的是LinkNode*,我懵了。

      面试官:问我能不能改成void。然后我脑子一抽,开始说形参改成引用的。

      面试官:(笑)我题目也不是引用呀(我一愣),那你先说说引用怎么改

      我就开始说,这里加个引用,后面再用head = t就行了。哪里加呢

      void reverse(LinkNode&* head)
      

      面试官:你这么写不对。(我继续改)

      void reverse(LinkNode* &head)
      

      面试官:也不对。(完了)

      我开始放弃这个点,开始扯其他的了。说这里用了引用和没有用引用有什么区别呢?

      我一开始说的很乱,然后又说好像是一样的,后面慢慢好了:引用表示的是指针的地址,不用引用表示指针指向的地址。(ok,上面的问题就算翻篇了)

    • 怎么改成题目的样子呢,也不用引用。

      我:把最开始的head记录下来为h,在最后的时候把htvaluenext交换,传入的那个指针就变成新的head啦。

      面试官:只需要这样就行了吗?

      我:(想不出来了)

      面试官指出了不对的地方,交换了头尾之后,之前1<-2<-3<-4<-5里面的2还是指向之前的尾(也就是现在的头)。。。

      我恍然大悟,还要把翻转后的倒数第二个节点记录下来,在头尾交换之后,再次指向现在的尾。

    • 面试官:你直到你之前为什么运行不了这个程序了吗?(我试了运行,有报错)

      我:(看了看)还是不知道

      面试官:(开始提示)你的l1,l2,l3指向什么

      我:!!!还没new!!!

    (结束)

  2. 升序再降序的数组,找到最大值。

    这题就很简单了,找最大值,O(n)肯定是能找到的,这种算法就不用说了。我就直接写的二分查找的方法。

    #include 
    #include 
    using namespace std;
    int binary_find(vector<int> v, int l, int r){
    	int mid = (l+r)/2;
    	if(v[mid] >= v[mid-1]&&v[mid] <= v[mid+1])
    		return v[mid];
    	if(v[mid] >= v[mid-1])
    		return binary_find(v, mid+1, r);
    	if(v[mid] <= v[mid+1])
    		return binary_find(v, l, mid-1);
    }
    int main(){
    	vector<int> v;
    	for(int i = 0; i < 6; i ++)
    		v.push_back(i);
    	for(int i = 5; i >= 0; i ++)
    		v.push_back(i);
    	int ans = binary_find(v, 0, v.size()-1);
    	cout << ans;
    	return 0;
    }
    
    • 面试官:你这mid+1和mid-1可能会越界

      我:确实还没考虑(改)

      int binary_find(vector<int> v, int l, int r){
      	if(r-l <= 1) return max(v[l], v[r]);
      	int mid = (l+r)/2;
      	if(v[mid] >= v[mid-1]&&v[mid] <= v[mid+1])
      		return v[mid];
      	if(v[mid] >= v[mid-1])
      		return binary_find(v, mid+1, r);
      	if(v[mid] <= v[mid+1])
      		return binary_find(v, l, mid-1);
      }
      

      我:只有当范围小于3个数的时候,才有可能出现越界的情况

    • 面试官:你这种迭代叫什么

      我:???

      面试官:那换种说法,这样为什么能够快速的解答,这种叫伪递归。(百度:尾递归)

      我:???

      面试官:算了

    • 面试官:怎么改成非递归

      我:巴拉巴拉

c++基础知识

  1. new的作用
    • 分配空间
    • 构造函数
    • 初始化
  2. 一个程序中new了之后,要怎么样:delete
  3. 不delete会怎么样:内存泄漏
  4. 怎么样防止内存泄漏:智能指针
  5. 智能指针怎么样防止内存泄漏:有个引用计数,当有指针指向的时候,+1,不指向的时候-1,为0的时候delete。
  6. 在哪里delete?(这里我半天没理解过来,问清楚了是程序的位置,然后又纠结了半天,最后说是在析构函数)
  7. delete和delete[]:一个是单个一个是批量

操作系统

  1. 进程的存储空间知道吧:知道,虚拟内存

  2. static声明的变量存在哪个区:。。。没答出来

  3. 进程和线程的区别

  4. 问我有没有写过多线程编程:没有

  5. 一个进程里不同的线程访问的资源在哪:在进程里

  6. 它们可以同时访问相同的资源吗:不行

  7. 那操作系统怎么办(黑人问号脸,不理解)一个线程访问后,把资源锁起来,其他线程来了只能阻塞,等那个线程用完后,阻塞再解除,按顺序访问。

  8. 你这是操作系统做的吗?不是,是程序员

  9. 那你再重新想想。我:。。。

  10. 那我换个场景:有一本书,有很多人要看,有很多人要写,怎么办?

    我:说出了读写锁的原理(这些其实我知道)

    面试官:那你这相当于加了一个读写锁

    (面试官貌似知道了我懂类似的知识,但是理解不了他前面说的话。我也才知道,原来这些锁是操作系统做的)

  11. 你再说说还有哪些东西可以实现这类问题?信号量(我还打算继续说来着)

  12. 面试官立马接着问:信号量适合在什么地方用?

    我:。。。

    面试官:看来这些方面你都没什么实践呀

    我:是的,我都是在考研的时候学的,看的都是书本上的东西。

计算机网络

  1. TCP和UDP的区别:一个是可靠的,一个是不可靠的

  2. TCP怎么实现可靠性:序列号、三次握手、四次挥手、拥塞控制

  3. 说一说三次握手

  4. 用UDP的话,怎么尽可能实现可靠性

    我:加上三次握手、四次挥手?

    面试官:你都用的是UDP了,还怎么连接(隔着屏幕和口罩感觉到了面试官的无奈)

    我:加上序列号,ack,重传机制

    面试官:还有吗

    我:。。。(好几分钟)想不到了

  5. 四次挥手中,主动断开方接受到ack时,是什么状态?

    我:established_wait_2,这些名字我不太记得(小声)

    面试官:主动断开方接受到FIN时,是什么状态?

    我:TIME_WAIT(不知道对不对)

    面试官:这个阶段主动断开方在做什么

    我:等待被动断开方的回应,如果被动方没有接受到主动方的ack,它会重传一次FIN

    面试官:如果一台服务器中有很多连接都处于TIME_WAIT状态,有什么影响

    我:影响其他连接的信息传输

    面试官:具体点

    我:。。。不知道

    面试官(提示):每一个连接都有什么

    我:。。。socket

    面试官:对。socket里面除了要保存IP地址之外还要保存什么?

    我:。。。(很久之后)

    面试官(提示):http协议巴拉巴拉¥%&…………,http协议的端口是80吧。所以?

    我:对,服务器里面端口是有限的,大量的TIME_WAIT连接会占用大量的端口号。(面试官已经提示到家了)(汗颜)

STL

  1. stl用过吧:嗯

  2. 说一说vector/map/unordered_map的实现

    我:vector就是数组,内存是动态分配的

    面:怎么动态分配的

    我:(STL源码分析)

    面:那map呢

    我:红黑树

    面:unordered_map

    我:哈希表

    面:底层实现是什么

    我:用的链表数组的方法。……&&*()¥%……

    面:还有其他的方法吗

    我:数组,线性探测法、二次探测法

    面:具体的

    我:¥%%……&&*

    面:没什么问题了,再来补一个题目吧

  3. 下面的代码有错吗

    vector<int> vec(5, 1);
    auto it = vec.begin() + 3;
    for (int i = 0; i < 10; ++i)
    {
        vec.insert(it, i);
    }
    

    我:没有,应该没有吧(小声逼逼)

    面:执行完了之后vec是什么样

    我:能提示一下第一句吗。。我从来没用过这种初始化(卑微)。

    面试官非常慷慨的告诉了我

    我:111987654321011

    面:那你自己写个删除第3-5个元素的代码吧

    #include 
    #include 
    using namespace std;
    int main() {
        vector<int> v(10, 1);
        for(auto i = v.begin()+3; i != v.end() -5 ; i = v.begin() +3){
            // 写代码的时候问了一下,我说我之前从来没有直接用过v.begin()+3这样的写法,之前的第二句的正确
            // 性是凭我自己的想法想的。。。
            // 面试官:顺序存储的容器可以这样写(万分感谢(泪目))
            v.erase(i);
        }
    }
    

    我:这里迭代器会失效

    面:那之前的插入呢

    我:也会失效

    面:再补一个算法题吧

算法(补)

面:topk问题

我:最大堆

面:时间复杂度

我:O(klog(n))

面:数据量n特别大呢

我:有多大(还没意识到问题)

面:1000亿

我:(开始算log(1000亿)等于多少)

面:内存不够(摊牌了)

我:。。。用分治,每次内存存进去,然后最大堆算出这个里面最大的数,把所有算出来的这些再求最大的k个(我同时也说出了不足)但是这个内存里面的数据算出来的最大值可能还不如另外一个内存里的前k个之外了。

面:嗯。。。

我:那就每次只算出最大的一个,然后循环

面:放弃堆吧。。。

我:那就用快排的思想

我:每次内存存进去的数,用快排的思想把它分来。因为快排一次只确定一个数的位置,把这个数的右边(比它大)记录下来,每次存进内存都把它记录下来,一轮过后再把记录下来的这些数,放在一起放进内存进行和上面一样的操作。直到最后只剩下比内存能装下的时候。用上面的思想直到确定那个数的位置正好是第k大的数,那么右边的数就是要求的了

面试官中间说了几句什么我忘了,我一直在哗啦啦说我的想法。。我说完了面试官就没继续问了

结尾

面:你有什么问题想问我吗

我:你们是腾讯微信哪个部门

面:搜索应用部门。搜一搜

我:哦,请问腾讯、微信面试比较看重的是哪方面的知识呢

面:c++语法、操作系统、计算机网络的基础知识

我:网络编程这块呢

面:也有

我:我没其他问题了

面:你现在在哪

我:湖南

面:看你介绍,有ACM经历,成绩怎么样

我:只有省赛二等奖

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