【每日刷题3.12】5道算法+15道面试 – 阿V

感觉算法太占时间了,而且刷的差不多了,现在开始专攻面试!加油~明天阿里笔试。

面试题 (一面-项目介绍+基础面)

1. 自我介绍 (游戏测试工程师)

看了多篇文章,说自我介绍不能太短,最好是三分钟,哈哈哈,我尽力描述。

HR你们好,我叫zzw,21岁,来面试游戏测试工程师的,就读于广东工业大学数字媒体技术专业,是一名热爱玩游戏又热爱开发游戏的网瘾少年,学校课程里的游戏开发大作业,都是完全负责程序代码方面,当然我也喜欢参与策划,课外也热爱自己捣鼓游戏开发,自己开发过几款游戏demo,都剪成视频上传到了B站,最满意的一款demo就是雷霆战机,播放量过万,在开发的过程中,遇到过许许多多的bug和问题,没系统学过怎么测试,都是自己摸索出bug的源头并修复。现在使用最频繁的是C++,因为最近半年刷算法都是用C++。

当然除了虚拟游戏,现实中我非常热爱运动,因为没有健康的体魄就玩不了游戏了,每天都会去跑步健身,之前爱好街舞,大二还担任了一年的舞蹈俱乐部社长,举办过不少活动,荣获四星级社团。乐于与人交往,在与人交往的过程中,学习如何做人,如何更好的与人配合。

之所以选择游戏测试工程师这个职业,因为很想从事游戏相关的职业,而所有职业中游戏测试工程师是最符合的,测试游戏可以令游戏质量上升,因为是一名游戏玩家,舒服的游戏体验是每个玩家都希望的,而测试游戏的过程中,可以学习到很多游戏开发的知识,这也是我渴望的。所以我想带着兴趣和梦想来担任这份工作,以上就是我的自我介绍,谢谢大家。

2. 介绍项目

雷霆战机项目:

游戏玩法:驾驶飞机躲避弹幕,吃比自己体型小的敌机进行升级,类似于大鱼吃小鱼的玩法。

遇到难题(对于当时的我来说):

1. 飞机类型与子弹类型如何做到同时匹配,解决办法是:将飞机类型和子弹类型用字典存储在一起,修改飞机的时候同时修改子弹。

2.飞机升级,子弹数量增加要如何增加,就是如何均匀地分布在飞机周围,解决办法是:在飞机周围提前创建好空对象,位置和编号都自己设定好,子弹增加时,获取对应编号的位置添加上去就行。

从中学习到了什么:

了解了飞行类游戏的玩法,相关设计模式的原理,例如:观察者模式。以及子弹的规则生成,敌机属性与AI的搭建。

3. TCP和UDP的联系和区别

 TCP(传输控制协议),是面向连接,可靠,基于字节流的传输协议,只支持单播,可以全双工通信,拥有拥塞控制,流量控制。建立连接使用三报文握手,断开连接使用四报文挥手。

UDP(用户数据报协议),是无连接,不可靠,基于报文流的传输协议,支持单播、多播、广播,不可以全双工通信。

4.  设计一个可靠的UDP协议应该怎么做?

 首先思考UDP怎么不可靠?UDP在传输过程中会出现丢包、数据不完整、乱序等问题。根据这些问题一一解决。

防止丢包:加入确认和重传机制,类似于TCP的Ack机制

数据不完整:加个16或32位的CRC验证字段

乱序:加个数据包序列号SEQ

5. 微信是使用TCP还是UDP

 根据TCP和UDP的原理,微信的视频通话,语音通话应该使用了速度更加的UDP,而文本消息等使用TCP确保信息准确。

但网上了解到,微信登陆验证等采用HTTP,而文本消息,视频通话等使用了TCP长连接,通过心跳包来维护长连接,300s一个心跳。

6. 进程和线程的联系和区别

 进程是表示资源分配的基本单位,线程是进程中执行运算和调度的最小单位。

1. 一个线程只能属于一个进程,而一个进程可以拥有多个线程。

2. 资源分配给进程,同一进程的所有线程共享该进程的所有资源。

3. 进程拥有独立的地址空间,进程都是建立在虚拟内存的基础上,而线程没有独立的地址空间。

4. 进程比线程健壮,一个进程崩溃不会影响其他进程,而一个线程崩溃会导致整个进程崩溃。

5. 进程执行开销大,而线程依附于进程,执行开销小。

7.  单例模式

 首先什么是单例模式?因程序需要,有时某个类只需要一个对象,例如:设备管理器,数据池等。

单例模式特点:1. 全局只有一个实例,禁止赋值和拷贝  2.用户通过接口获取实例

实现单例的几种方式;

1. 懒汉式(Lazy-Initialization)的方法是直到使用时才实例化对象,问题:

        1.线程安全问题,不同线程同时创建该类,可能导致多个实例出现,解决办法加锁。

        2.内存泄漏,由于static申请在静态存储区,无法直接delete,只能靠系统自己处理。

#include <iostream>
// version1:
// with problems below:
// 1. thread is not safe
// 2. memory leak

class Singleton{
private:
    Singleton(){ //修改默认构造函数
        std::cout<<"constructor called!"<<std::endl;
    }
    Singleton(Singleton&)=delete; //删除拷贝构造函数
    Singleton& operator=(const Singleton&)=delete; //删除赋值运算符函数
    static Singleton* m_instance_ptr; //创建静态对象
public:
    ~Singleton(){ //修改析构函数
        std::cout<<"destructor called!"<<std::endl;
    }
    static Singleton* get_instance(){ //创建对象
        if(m_instance_ptr==nullptr){
              m_instance_ptr = new Singleton;
        }
        return m_instance_ptr;
    }
    void use() const { std::cout << "in use" << std::endl; } //const放函数后面表示该函数一切都不可修改
};

Singleton* Singleton::m_instance_ptr = nullptr; //初始化单例对象为空

int main(){
    Singleton* instance = Singleton::get_instance();
    Singleton* instance_2 = Singleton::get_instance();
    return 0;
}

2. 线程安全、内存安全的懒汉式单例 (智能指针,锁)

#include <iostream>
#include <memory> // shared_ptr
#include <mutex>  // mutex

// version 2:
// with problems below fixed:
// 1. thread is safe now
// 2. memory doesn't leak

class Singleton {
public:
	typedef std::shared_ptr<Singleton> Ptr; //使用智能指针

	~Singleton() {
		std::cout << "destructor called!" << std::endl;
	}

	Singleton(Singleton&) = delete; //禁止拷贝构造函数
	Singleton& operator=(const Singleton&) = delete; //赋值运算符操作

	static Ptr get_instance() {

		// "double checked lock"
		if (m_instance_ptr == nullptr) {
			std::lock_guard<std::mutex> lk(m_mutex); //线程加锁
			if (m_instance_ptr == nullptr) {
				m_instance_ptr = Ptr(new Singleton);
			}
		}
		return m_instance_ptr;
	}


private:
	Singleton() {
		std::cout << "constructor called!" << std::endl;
	}

	static Ptr m_instance_ptr; //创建静态对象
	static std::mutex m_mutex;
};

// initialization static variables out of class
Singleton::Ptr Singleton::m_instance_ptr = nullptr;
std::mutex Singleton::m_mutex;

int main() {
	Singleton::Ptr instance = Singleton::get_instance();
	Singleton::Ptr instance2 = Singleton::get_instance();
	return 0;
}

3. 最推荐的懒汉式单例(magic static )——局部静态变量

#include <iostream>

class Singleton
{
public:
    ~Singleton(){
        std::cout<<"destructor called!"<<std::endl;
    }

    Singleton(const Singleton&)=delete;
    Singleton& operator=(const Singleton&)=delete;

    static Singleton& get_instance(){
        static Singleton instance;
        return instance;
    }
private:
    Singleton(){
        std::cout<<"constructor called!"<<std::endl;
    }
};

int main(int argc, char *argv[])
{
    Singleton& instance_1 = Singleton::get_instance();
    Singleton& instance_2 = Singleton::get_instance();
    return 0;
}

 8.  C++ STL是什么

 STL:标准模板库,一些容器、算法和其他一些组件的集合,容器包括vector、list、set、map等

有什么作用呢?使用 STL 可以更加方便灵活地处理数据

9. 常见的数据结构

 数组、队列、堆、栈、树、图、链表等

 10. C++内存分配的方式

 有三种:静态存储区分配、栈上分配内存和堆上分配内存。、

静态存储区分配内存:在程序编译时就分配好了,程序的整个运行期间都存在,例如全局变量,static变量。

栈上分配内存:系统自动分配,例如函数内部的局部变量,随着函数结束而删除。

堆上分配内存:动态分配内存,例如new、malloc。

11.  malloc/free和new/delete的区别

 共同点:都是从堆上申请空间,并且需要用户手动释放。

不同点:

1. malloc和free是函数,new和delete是操作符

2. malloc申请的空间不会初始化,new可以初始化。

3. malloc申请空间要手动计算空间大小,new只需在其后输入空间类型即可。

4. malloc的返回值是void*,new返回空间类型。

5. malloc申请空间失败,返回NULL,new申请失败,抛出异常。

12.  C++ vector 容器

 什么是vector?vector是一个封装了动态大小数组的顺序容器

特性:

1. 容器内元素按严格的线性顺序排序,查找的时间复杂度为O(1)。

2. 添加元素时会进行动态分配内存,使其快速增删。

常用函数:push_back(),pop_back(),empty() ,sort()等。

13. HTTPS是什么?

想了解HTTPS是什么?就要先了解HTTP? 就要了解TLS/SSL 工作原理及握手过程。

传输层安全性协议 TLS(Transport Layer Security),及其前身安全套接层 SSL(Secure Sockets Layer)是一种安全协议,目的是为互联网通信提供安全及数据完整性保障。

HTTP:超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。

HTTPS:是以安全为目标的 HTTP 通道,是 HTTP 的安全版。HTTPS 的安全基础是 SSL。SSL 协议位于 TCP/IP 协议与各种应用层协议之间,为数据通讯提供安全支持。

14.  HTTP的请求有哪几种?各有什么用?

1.GET:请求指定的页面信息,并返回实体主体。

2. HEAD:类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头。

3. POST:向指定资源提交数据进行处理请求。

4. PUT:从客户端向服务器传送的数据取代指定的文档内容。

5. DELETE:请求服务器删除指定的页面。

6. CONNECT:将连接改为管道方式的代理服务器。

7. OPTIONS:允许客户端查看服务器性能

8. TRACE:回显服务器收到的请求,主要用于测试。

算法题

1. 两个数对之间的最大乘积差

 贪心算法。

代码详情:

class Solution {
public:
    int maxProductDifference(vector<int>& nums) {
        sort(nums.begin(), nums.end()); //排序数组

        return ((nums[nums.size()-1] * nums[nums.size()-2]) - (nums[0] * nums[1]));
    }
};

 通过情况:

 2. 数组拆分 I

 贪心算法。

代码详情:

class Solution {
public:
    int arrayPairSum(vector<int>& nums) {
        sort(nums.begin(), nums.end()); //数组排序
        int n = nums.size();
        if (n == 1) return nums[0]; //边界判断

        int res = 0; //存储最终答案
        for (int i = n - 2; i >= 0; i -= 2){ //贪心算法,每次选最后两个的前一个为最小
            res += nums[i];
        }

        return res;
    }
};

明天晚上就阿里笔试啦!!!加油~

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
青葱年少的头像青葱年少普通用户
上一篇 2023年12月27日
下一篇 2023年12月27日

相关推荐