腾讯2021暑期C++天美工作室游戏开发实习面试题&面经

Posted 遥远的歌s

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了腾讯2021暑期C++天美工作室游戏开发实习面试题&面经相关的知识,希望对你有一定的参考价值。

前段时间投了腾讯互娱群下的天美工作室,结果10分钟不到就收到了面试通知,约到四天后的晚上,我甚是期待,奈何这次面试给我上了一课,足足面试了我三个半小时多,而且还凉凉了,真是身心疲惫呀。
首先面试一开始,面试官给我直接说我们先来作题,我心想怕是动态规划的题就凉凉,果然面试官给了我三道题,第一题就是动态规划,看了一眼果断进军第二题。

第一题、获得目标数的总和

给你一个非负的数组nums,和一个key值,你可以再nums中每两个数中间任意加入`-`或者`+`,
使得其运算可以得到目标数key,请你返回能得到目标数key的所有方法的总和。

首先想到深度优先,遍历nums,从开头开始+,只要小于key并且没有达到数组尾部,就继续加,直到大于key返回上一层变为-后继续向后+,以此类推,但是结果时间超时。而且废了我20分钟,我立刻放弃此题写下一题。后来才知道动态规划可以解决。

我已经将第一题的思路写了一篇博客,欢迎大家提供不一样的思路动态规划01背包的拓展问题

第二题、LRU的模拟实现,要求查询,插入复杂度都是O(1)

题目链接LRU缓存
这道题我用单链表实现的,面试官看完代码就问我时间复杂度,很显然不是O(1),他不是很满意。下来我自己想了想结合大佬提供的思路,使用listunordered_map来实现

数据结构

	size_t cap;//缓存容量
    list<pair<int,int>> cache;//缓存块链表
    unordered_map<int, list<pair<int, int>>::iterator> mp;//用来标记key值再list中迭代器的位置

思路
put的时候判断key值在mp中是否存在,不存在,则将pair<int,int> (key,value)头插到到cache的头部,如果存在,则将其取出并且插入到cache的头部。
上述执行完,只需判断当前cache.size(),是否大于容量cap,如果大于,则对list进行尾删,同时将mp中对应的key删掉。

get的时候,同样先判断当前key值在mp中是否存在,不存在则依据题目要求返回-1,否则表示存在。
接下来从mp中获取其对应的迭代器,从而获得该结点的信息,然后将该结点从这个位置删掉,再将其头插到cache中即可,再更新mp中其对应的迭代器位置即可

class LRUCache 
public:
    LRUCache(int capacity) 
        :cap(capacity)    
    
    int get(int key)
    
        auto it = mp.find(key);
        if(it == mp.end())  return -1;
        auto pos = it->second;//获取当前key值在cache中对应的位置
        int res = pos->second;//获取value值
        cache.push_front(pair<int,int> (pos->first,pos->second));//将新节点头插
        cache.erase(pos);//删除旧节点
        mp[key] = cache.begin();//更新key对应的迭代器位置
        return res;//返回
    
    void put(int key,int value)
    
        auto it = mp.find(key);//从mp中查询key是否存在
        //如果不存在,则表示要更新
        if(it == mp.end())
        
        //将key和value构成一个新节点头插到cache中
            cache.push_front(pair<int,int> (key,value));
            mp[key] = cache.begin();//将key以及cache中key对应的迭代器的位置插入到mp中
        
        //表示存在
        else
        
        //获取key值当前在cache中的位置
            auto pos = it->second;
            cache.erase(pos);//删除该结点
            cache.push_front(pair<int,int> (key,value));//构建新的检点头插到cache中
            mp[key] = cache.begin();//更新mp中key在cache中国的迭代器的位置
        
        //判断当前cache的大小是否超过cap
        if(cache.size() > cap)
        
        //超过则对cache进行尾删
            mp.erase(cache.back().first);//先从mp中删除对应的key值
            cache.pop_back();//再进行尾删
        
    

public:
    size_t cap;
    list<pair<int,int>> cache;
    unordered_map<int, list<pair<int, int>>::iterator> mp;
;

第三题、有效的括号字符串

题目链接:有效的括号字符串
这个题还算友好
给定一个只包含三种字符的字符串:( ,) 和 *,写一个函数来检验这个字符串是否为有效字符串。有效字符串具有如下规则:

任何左括号 ( 必须有相应的右括号 )。
任何右括号 ) 必须有相应的左括号 ( 。
左括号 ( 必须在对应的右括号之前 )* 可以被视为单个右括号 ) ,或单个左括号 ( ,或一个空字符串。
一个空字符串也被视为有效字符串。

示例 1:

输入: "()"
输出: True

示例 2:

输入: "(*)"
输出: True

示例 3:

输入: "(*))"
输出: True

注意:
字符串大小将在 [1,100] 范围内。
写这道题快完的时候网断了,重新连接上面试后之前所有代码全没了,面试官直接让我从写,从新计时一小时(心态都崩了)
言归正传,这和我之前做的一个题很类似,只不过这道题 *不仅可以代替()还能代替空格,首选用栈,写到一半发现有种情况没考虑直接从来,又耽误了很长时间,之后使用双栈搞定

思路
定义两个栈st1和st2分别用来存储(*的下标,那么分为以下几种情况:

  1. 如果为(则其下标入栈st1,如果为*则其下标入栈st2。
  2. 如果为)则优先从st1中判断是否存在(的下标,存在则出栈,继续向下遍历字符串,如果st1为空则再判断st2中是否存在*的下标,存在则出栈,再继续向下遍历。如果st1和st2都为空,表示没有或者*与之匹配,返回false。
  3. 如果遍历完字符串后,st1为空,则返回true,否则就要和st2中的*进行匹配,当st1的栈顶元素小于st2的栈顶元素则st1和st2同时出栈,否则返回false。
  4. 最后返回st1是否为空即可
class Solution 
public:
    bool checkValidString(string s) 
        stack<int> st1,st2;
        for(int i = 0;i<s.length();i++)
        
        //如果是(或者*则入栈
            if(s[i] == '(')
                st1.push(i);
            else if(s[i] == '*')
                st2.push(i);
            //是)则进行匹配
            else
            
                if(!st1.empty())
                    st1.pop();
                else if(!st2.empty())
                    st2.pop();
                else
                    return false;
            
        
        //剩下的(和*进行匹配
        while(!st1.empty() && !st2.empty())
        
            if(st1.top() > st2.top())
                return false;
            st1.pop();
            st2.pop();
        
        return st1.empty();
    
;

到这,三道题我就写了两道,其中第一道没有得到完美答案,第二道没让面试官满意。接下来开始问基础知识。
以下罗列
1.同学你了解C++的多态吗?多态是如何实现的?
2.构造函数可以是虚函数吗?为什么?
3.析构函数可以是虚函数吗?为什么?
4.快速排序的原理是什么?(霍尔划分,挖坑法,前后指针能说的都说了)
5.快排如何优化?(随机数法,三数取中,加入插入排序,递归变为非递归等能说的也都说了)
6.给你5000W数量级的数据,如何快速定位到我要找到的数据?(哈希表,B+树)
7.如果一个机器存不下5000W数量级的数据,怎么办?(当时脑子有点秀逗,答了个插入外存条,面试官直接笑了,就跳过了这个问题,现在想想,应该是使用布隆过滤器)
8.C++中提供的强制类型转换有哪些,有什么区别?
9.有了解过LINUX操作系统吗?它有什么优点?
10.Linux下I/O多路复用机制有哪些?区别是什么?(epoll,poll,select它们之间的区别)

重点来了,问完上述问题,面试官给我来了一句:前面三道题你写的不是很理想,来我们加试50分钟,再给你两道题写。
我内心:?????还能加试????
于是硬质头皮答应了,又给了我两个题
第一个就是自己实现memcpy函数,这个主要就是注意内存重叠的问题,拷贝的思路都么没问题,但是不知当时怎么了,犯了一个致命错误,void类型我返回了一个char*类型,导致面试官就不再看我的代码,直接看下一道题。

最后一题是以逗号为分隔符反转字符转中的单词
例如

输入:hello world,you bless god
输出:world hello,god bless you

这个没什么难度,先以,为分界位置全部反转一次,再以,和空格为分界位再反转一次就行

void reverse_str(string& str,int left,int right)

  while(left <= right)
  
    char tmp = str[left];
    str[left] = str[right];
    str[right] = tmp;
    left++;
    right--;
  

void str_reverse(string& str)

  int begin = 0,start = 0,end = 0,flag = 0;
  for(int i = 0;i<str.length();i++)
  
    if(str[i] == ' ' || str[i + 1] == '\\0')
    
      if(str[i + 1] == '\\0')
        end = i;
      else
        end = i - 1;
      flag = start;
      reverse_str(str,start,end);
      start = i + 1;
    
    if(str[i] == ',' || str[i + 1] == '\\0')
    
      if(str[i + 1] == '\\0')
        end = i;
      else
        end = i - 1;
      if(flag != start)
      
        reverse_str(str,start,end);
        reverse_str(str,begin,end);
        start = begin = i + 1;
      
      else
      
        reverse_str(str,begin,end);
        start = begin = i + 1;
      
    
  

终于,面试官问我你还有什么要问我的吗?我就简单问了下工作环境以及工作量。就结束了历时三个半小时的面试,真的身心疲惫。
第二天看了眼面试流程,变灰了,就知道凉凉了,虽然没有过,但是还是学到了不少,希望今后能够面试顺利!!

以上是关于腾讯2021暑期C++天美工作室游戏开发实习面试题&面经的主要内容,如果未能解决你的问题,请参考以下文章

福利|腾讯云/网络产品中心后台开发和大数据开发的部门暑期实习内推

腾讯暑期实习生线上(软件开发 移动开发)笔试涉及的知识点

2020年腾讯实习生C++面试题&持续更新中

2020年腾讯实习生C++面试题&持续更新中

腾讯2017暑期实习生编程题

2020年腾讯实习生C++面试题&持续更新中