第4天:美团点评2020校招测试方向笔试试卷分析
前言
明天有一场百度的测试工程师的笔试,因此今天做了一场关于美团的测试岗的笔试试卷。一共有九道题,四道问答题和五道编程题。其中的四道问答题是有关测试的专业问答题,五道题是编程题,感觉还好,难度差不多,不太难,比起之前腾讯、阿里、网易的NLP算法岗的编程题要简单多了。至于为什么本人算法岗转测试岗,那是由于今年的算法岗过难了,供远远大于求。可是本人也没有特别好的项目,也没发过论文。因此,本人就转测试了。接下来,本人给大家详细介绍这几道题。
试题分析
一、问答题
因为这4道题没有刚性的标准答案,因此不记入总分,因为本人没有系统学过测试相关的理论,因此本人只是将分享自己的答案,简单地从计算机网络、java方向考虑问题。但是应该有错误,希望大家指教。 1、当使用美团团购购买套餐后,后台发生了哪些业务流程?
1.通过域名,dns解析到对应ip,请求网关,通过负载均衡和转发请求到对应服务器 2.三次握手,请求购买套餐接口,查询用户token是否有效,数据库数据是否有库存,是否符合情况 3.符合接口逻辑,返回success,并通过kafka等消息将操作 发送给别的服务 4.将返回数据返回给浏览器,浏览器解析html代码,呈现用户
2、当用户第一次打开并登陆外卖App后会看到App的首页,打开和登陆外卖App的过程中发生了哪些具体的动作行为以及可能导致的缺陷?
用户输入密码,App把这些信息用RSA公钥加密:(用户名,密码,时间,mac,随机数),并发送到服务器。 服务器用RSA私钥解密,判断时间(可以动态调整1天到7天),如果不在时间范围之内,则登陆失败。如果在时间范围之内,再调用coreservice判断用户名和密码。 这里判断时间,主要是防止攻击者截取到加密串后,可以长久地利用这个加密串来登陆。 如果服务器判断用户成功登陆,则用AES加密:(随机salt,用户名,客户端类型,时间),以(用户名+Android/IOS/WP)为key,存到缓存里。再把加密结果返回给客户端。 客户端保存服务器返回的加密串
3、当使用美团App扫描美团单车上的二维码后,发生了什么?
1、二维码识别:开锁URL、车辆ID、车辆GPS等 2、网络通信 3、业务逻辑判断:车锁状态正常、账号余额充足、用户身份正常、用户GPS位置正常 4、执行开锁、计费开始
4、当前的移动互联网产品,大都为以移动App形式呈现的一个典型的Client/Server或客户/服务器的体系结构:用户通过UI操作触发移动用户端发送一个网络请求给后台服务,众多后台微服务以及各种数据存储相互协作,得到用户想要的信息,并发送回移动应用端。移动端根据接收到的响应,展示不同的信息给用户。 假设当你在移动App中,点击一个按钮,比方说,美团的登陆按钮,如果从移动App的界面看起来,任何事情都没有发生,你将如何分析定位问题大致发生在什么地方?
界面未给出响应的原因: 程序问题: 1、按钮的监听事件未正确调用,或者干脆就没有添加监听 2、监听确认被调用,但监听过程出现错误或异常,例如参数传输失败。 3、前端调用接口错误,如后端出现运行时异常,没有给出相应的提示消息 设备问题: 1、网络延迟,响应没有及时出现,超时 2、手机卡顿,出现死机现象 3、响应被中断
二、编程题
1、删除字符
(1)、题目描述:
将给定的字符串,按照规则删除字符,输出删除后的字符串。删除规则为:相同字符连续,则删除,如”aaaab”删除后的字符串为”b” 。注:仅是单个字符连续才删除,如babababa则不能删除;
(2)、输入描述:
输入数据有多组,每组一行,仅包含数字和英文字母,不包含转义等其他特殊字符,输入数据最大长度为10;
(3)、输出描述:
对于每个测试实例,要求输出按规则删除后的数据,每个测试实例的输出占一行。如果删除后有字符,直接输出删除后的字符;如果删除后为空,则输出”no”
(4)、示例1
输入 a aaaaabbbb
输出 a no
(5)、解题思路 思路其实很清晰,题目的意思就是遇到连续的字母就删除,不过我觉得这道题的来源与剑指offer中的第一个只出现一次的字符,当时这道题的解决办法是用的是hashcode来解决。只不过剑指offer拿到题是要找出第一次出现的字符,而本题是删除连续重复的字符。因此核心都是要找出重复字母的下标进行删除。其实还有一道与本题相关的编程题,也是差不多——删除链表中重复的结点。只不过是关于数字的链表,删除重复的链表。另外吧结点也删除了。当时这道题不过是提前排好序的数字,因此只需要直接删除也可。我也可以分别通过迭代和递归的方法来定义一个先驱结点dummyHead和链表相连 null->1->2->3->3->4->4->5。接着定义两个结点,一个node=phead next=phead.next,如果两个结点值不相等,都相后走一步,否则,node不动,走到next.val!=node.val;最后prev.next=next.next。具体实现请查看文章。因此本题我们可以将这两道题结合起来,可以利用这两道题的思路整体结合起来,可以直接利用一个双指针的思路进行实现,我们可以用java实现:
package 面试;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (in.hasNext()) {
String str = in.nextLine();
StringBuilder sb = new StringBuilder();
// i记录连续子串的头部
for (int i = 0; i < str.length(); i++) {
// j为移动指针,记录连续子串的尾部
int j = i;
// 若后一个字符跟当前一样,则j后移一位
while (j + 1 < str.length() && str.charAt(j) == str.charAt(j + 1))
j++;
if (i == j)
// ij相等说明不是连续的,拼接之
sb.append(str.charAt(i));
else
// 当前子串是连续,跳过
i = j;
}
if (sb.toString().equals(""))
System.out.println("no");
else
System.out.println(sb);
}
}
}
测试的结果如下:
当然我们也可以左右两边都不相同,就保留,第一个和最后一个特殊处理一下就可以了。具体用python实现如下:
while True:
try:
input_str = input()
result = ""
for i in range(len(input_str)):
if len(input_str) == 1:
result = input_str
break
if i == 0:
if input_str[i + 1] != input_str[i]:
result = result + input_str[i]
elif i == len(input_str) - 1:
if input_str[i - 1] != input_str[i]:
result = result + input_str[i]
else:
if input_str[i - 1] != input_str[i] and input_str[i + 1] != input_str[i]:
result = result + input_str[i]
if len(result) == 0:
print("no")
else:
print(result)
except:
break
测试的结果如下:
2、寻找最小子字符串
(1)、题目描述:
小美和小团在玩一个游戏,小美任意给出一个大字符串str1以及一个独立的小字符串str2,小团需要从这个大字符串str1里找到包含独立小字符串str2中所有字符的最小子字符串str3; 例如,小美给出一个大字符串"meituan2019"和一个子字符串"i2t",那么小团给出的答案就应该是"ituan2";
(2)、需要注意:
1、str1中有可能没有完整包含str2所有字符的情况,此时返回"",即为空字符串; 2、str1不会为空,但str2有可能为空,此时返回整个str1; 3、str2可能存在重复的字符,此时str3需要包含相等数量该字符;
(3)、示例1
输入 “meituan2019”,“i2t”
输出 “ituan2”
(4)、备注:
str1,str2 的长度均不超过100
(5)、解题思路 既然是包含它的最小子序列,那么序列的左右两边必定包含str2的字符,
- 自己构建hash函数表,记录每个单词出现的次数。
- 找出特殊情况,str2中某个字符的数量,少于str1中。
- 找出left,与right
具体用java和python实现如下: 1、用java实现如下:
package 面试;
public class Main2 {
public String getMinString (String str1, String str2) {
// write code here
if(str2==null||str2.length()==0){ return str1;}
int[] strA = new int[128];
int[] strB = new int[128];
int left = 0,right = 0;
for(int i=0;i<str1.length();i++){
strA[str1.charAt(i)]++;
}
for(int i=0;i<str2.length();i++){
strB[str2.charAt(i)]++;
}
// 没有完全包含所有字符,str2中有个字符多了几个或一个。
for(int k=0;k<str2.length();k++){//str.charAt()
if(strA[str2.charAt(k)]<strB[str2.charAt(k)]){
return "";
}
}
//find left
for(int k=0;k<str1.length();k++){
//保证相同数目的字符在范围内
if(--strA[str1.charAt(k)]<strB[str1.charAt(k)]){
left=k;
break;
}
}
for(int k=str1.length()-1;k>=0;k--){
if(--strA[str1.charAt(k)]<strB[str1.charAt(k)]){
right=k;
break;
}
}
return str1.substring(left,right+1);
}
}
测试结果如下:
2、用python实现如下:
# python
input_str = input()
father_str = input_str.split(",")[0].split(""")[1]
son_str = input_str.split(",")[1].split(""")[1]
result = ""
index_list = []
for letter in son_str:
_index = father_str.find(letter)
if _index in index_list:
_index = father_str.find(letter, _index+1)
index_list.append(_index)
if len(index_list) == 0:
result = father_str
else:
result = father_str[min(index_list):max(index_list)+1]
if -1 in index_list:
result = ""
print("""+result+""")
测试结果如下:
3、队列组合排序
(1)、题目描述:
一个班级男生和女生数量相同,老师要求男生女生进行排队,男生全部排在队列前面,女生紧跟着排在男生队列后面,形成一个队列,现在要求男生女生交叉排列并且第一位是男生,且每个人在在原队列中的顺序不变,如何来做?
(2)、要求:
交叉前:队列[男1,男2,男3,男4…男n,女1,女2,女3,女4…女n] 交叉后:队列[男1,女1,男2,女2,男3,女3,男4,女4…男n,女n]
(3)、输入描述:
输入第一行一个整数 n 表示有 n 个男生和 n 个女生 第 2 到第 n+1 行每一行有一个数字表示每个男生的编号 第 n+2 到第 2*n+1 行每一行有一个数字表示每个女生的编号
(3)、输出描述:
输出 2*n 行,每行一个名字表示交叉排列后队列中依次每个学生的编号
(4)、示例1
输入 3 1 2 3 4 5 6
输出 1 4 2 5 3 6
(6)、说明
男【1,2,3】+女【4,5,6】。交叉后变为:【1,4,2,5,3,6】
(7)、备注
1<=n<=10^5, 每个学生的标号互不相同,并且标号 x 满足: 1<=x<=10^9
(8)、解题思路 其实本题与剑指offer中的调整数组顺序使奇数位于偶数前面,剑指offer中的调整数组顺序使奇数位于偶数前面是将所有的奇数位于数组前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间相对位置不变。而本题其实是调整数组顺序使奇数位于偶数前面的具体实际应用。因此我们可以参考剑指offer中的调整数组顺序使奇数位于偶数前面。因此我们可以我们不仅要让奇数在偶数的前面,还要考虑奇数和偶数原来的相对位置不变。因此我们首先要寻找第一个奇数,并将其放在0号位置。然后将第一个奇数之前的元素全部往后移一位。依次再第一个奇数之后的元素中寻找奇数,并做移动操作,就可以保证原来的相对顺序。我们可以用java将其实现:
package 面试;
import java.util.ArrayList;
import java.util.Scanner;
public class Main3 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int size = 2*n;
ArrayList<Integer> list = new ArrayList<Integer>(2*n);
int[] arr = new int[n];
int[] brr = new int[n];
for (int i = 0; i <n; i++) {
arr[i] = sc.nextInt();
}
for (int i = 0; i <n; i++) {
brr[i] = sc.nextInt();
}
for (int i=0,j=0,k=0; k<size;k++) {
if(k%2==0) {//偶数位
System.out.println(arr[i]);
i++;
}
else {
System.out.println(brr[j]);
j++;
}
}
sc.close();
}
}
测试结果如下:
当然我们也可以用python实现:
while True:
try:
n = int(input())
x = []
y = []
for i in range(n):
x.append(int(input()))
for i in range(n):
y.append(int(input()))
for i in range(n):
print(x[i])
print(y[i])
except:
break
测试结果如下:
4、最大矩形
(1)、题目描述:
给定一个仅包含0和1的二维二进制矩阵,发现只包含1的最大矩形,并返回其面积。
(2)、输入描述:
输入一个仅包含’0’和’1’的二维字符数组。 第一行输入左大括号{,最后一行输入右大扩号}。 中间每行输入只包含’0’和’1’的字符数组(字符数组的长度不超过20),字符使用单引号”,字符之间使用逗号,替换,字符数组的开始和结束使用大括号{}。 (字符数组之间的个数不超过20)。
(3)、输出描述:
输出只包含字符’1’的最大矩形的面积。
(4)、示例1
输入 { {‘1’,‘0’}, {‘1’,‘0’} }
输出 2
(5)、示例2
输入 { {‘0’,‘0’}, {‘0’,‘1’} }
输出 1
(6)、解题思路 这里我们使用动态规划,具体我们用python实现:
class Solution:
def maximalRectangle(self, matrix) -> int:
if not matrix: return 0
height = len(matrix)
width = len(matrix[0])
heights = [0] * width
left = [0] * width # 初始化左边界为最左边界
right = [width] * width # 初始化右边界为最右边界
maxarea = 0
for i in range(height):
cur_left, cur_right = 0, width
# 更新当前行的高度
for j in range(width):
if matrix[i][j] == '1':
heights[j] += 1
else:
heights[j] = 0
# 更新左边界
for j in range(width):
if matrix[i][j] == '1':
left[j] = max(left[j], cur_left)
else:
left[j] = 0
cur_left = j + 1
# 是我们遇到的最右边的0的序号加1。当将矩形向左 “扩展” ,
# 不能超过该点,否则会遇到0。
# 更新右边界
for j in range(width - 1, -1, -1):
if matrix[i][j] == '1':
right[j] = min(right[j], cur_right)
else:
right[j] = width
cur_right = j
# 更新最大边界
for j in range(width):
maxarea = max(maxarea, heights[j] * (right[j] - left[j]))
return maxarea
s = Solution()
string = input().strip()
save = ''
save = save + string
while (string != "}"):
string = input().strip()
save = save + string
matrix = save.replace("{", "[")
matrix = matrix.replace("}", "]")
matrix = eval(matrix)
print(s.maximalRectangle(matrix))
测试结果如下:
5、最短送餐路程计算
(1)、题目描述:
美团外卖是知名的外卖平台,现在有一名新入职的外卖小哥。请你给他写一段程序根据外卖地图和交通拥堵情况,告诉他从“配送点”V0,到各个目的地的最短配送距离。其中拥堵程度可以与路径参数直接相加,例如:V0点拥堵,拥堵系数是2,那么在地图上V0点的3条线路的参数都要加2,由原来的1、2、7变为3、4、9再进行。
路径规划计算。路径参数越大代表路程越长。
(2)、输入描述:
输入数据只有一行,有三个int型参数,分别表示:目的地编号、拥堵节点编号和拥堵值。 例如:4 3 1,代表目的地是V4,在V3节点有拥堵情况,拥堵系数是1。
(3)、输出描述:
输出一个数字表示有起点V0到终点的最短距离
(4)、示例1
输入 4 2 1
输出 6
(5)、示例2
输入 5 4 1
输出 5
(6)、解题思路 这里很明显考察的是图的最短路径,因此有四种方法,深度或广度优先搜索算法,弗洛伊德算法,迪杰斯特拉算法,Bellman-Ford算法。我们这里用迪杰斯特拉算法,具体用java和python实现如下: 1、首先用java实现:
import java.util.*;
public class Main4 {
static int dijkstra(int[][] g, int n, int target, int k, int value){
boolean[] finished = new boolean[n];
int[] distance = new int[n];
Arrays.fill(distance, Integer.MAX_VALUE);
distance[0] = k == 0 ? value : 0;
if(k != 0) {
for(int i=0; i < n; i++)
if(i != k && g[k][i] != -1) {
g[i][k] = g[k][i] += value;
}
}
for(int i=0; i < n; i++) {
int t = -1;
for(int j=0; j < n; j++) {
if(finished[j]==false &&(t == -1 || distance[t] > distance[j])) {
t = j;
}
}
finished[t] = true;
for(int j=0; j < n; j++) {
if(g[t][j] != -1) {
distance[j] = Math.min(distance[j], distance[t]+g[t][j]);
}
}
}
return distance[target];
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int target = sc.nextInt();
int k = sc.nextInt(), value=sc.nextInt();
int n = 6;
int[][] g = new int[n][n];
for(int i=0; i < n; i++){
Arrays.fill(g[i], -1);
g[i][i] = 0;
}
g[0][1] = 1; g[0][2] = 2; g[0][3] = 7;
g[1][0] = 1; g[1][2] = 2; g[1][4] = 5; g[1][5] = 4;
g[2][0] = 2; g[2][1] = 2; g[2][4] = 4; g[2][3] = 4;
g[3][0] = 7; g[3][2] = 4; g[3][4] = 6;
g[4][1] = 5; g[4][2] = 4; g[4][3] = 6; g[4][5] = 3;
g[5][1]=4; g[5][4] = 3;
System.out.println(dijkstra(g, n, target, k, value));
}
}
测试结果如下:
2、接下来用python实现:
def f(t, v, c):
a = [0, 1, 2, 6, 6, 5]
if v == 0:
for i in range(1, 6):
a[i] += c
if v == 1:
a[1] += c
a[5] += c * 2
a[5] = min(a[5], 9)
if v == 2:
a[4] += c * 2
a[4] = max(a[4], 6)
a[3] += c * 2
a[3] = max(a[3], 7)
a[2] += c
if v == 3:
a[3] += c
if v == 4:
a[4] += c
if v == 5:
a[5] += c
print(a[t])
if __name__ == "__main__":
i = input().split(" ")
for t in range(len(i)):
i[t] = int(i[t])
f(i[0], i[1], i[2])
测试结果如下:
总结
最近的算法岗可谓是神仙打架,因此本人就投了测试岗,通过对公司真题的解答发现,公司的题目还是整体很注重基础算法的,并且考察的比较全面,着重考察的是我们对数据结构与算法的掌握程度,和我们平常练习的有所差别,我们还得继续努力,掌握好每个知识点。并且要学会学以致用。另外,我们发现还考察找规律,需要我们多方面发展。秋招已经好久了,需要我们刷真题了,需要思维转变,好好准备,希望2021届毕业的我们,都能有一份满意的Offer,Hang in there,you can do this.Time will there, Break a leg!!!
- Tomcat启动慢解决方法(本人CentOS7.4系统)
- Nginx软件部署配置过程
- iptables网络安全服务详细使用
- 未来哪个行业能赚钱,看百度、阿里、腾讯投资的企业你就知道了!
- Augmate公司应用分布式账本技术,将IOTA整合为物联网设备管理平台
- 一域名一年前六位数终端易主 是为了......
- 黑客通过Facebook Messenger传播加密货币挖掘恶意软件
- linq to sql的多条件动态查询(下)
- iptables网络安全服务详细使用
- iptables网络安全服务详细使用
- linq to sql的多条件动态查询(上)
- 极简区块链手册:什么是区块链?什么是比特币?
- Nginx+keepalived实现高可用
- 来一波Linux中查看cpu、磁盘、内存、网络的命令
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 腾讯云服务器Centos挂载数据盘的方法
- CentOS 8.0.1905 安装 ZABBIX4.4版本 (已验证)
- seaborn分类变量的汇总展示
- Linux查看PCIe版本及速率的方法
- android自定义滚轴选择器
- 虚拟机安装Linux rhel7.3操作系统(具体步骤)
- linux系统安装zookeeper 服务的方法
- 详解Linux中关于引号的那些事
- seaborn可视化数据框中的多个列元素
- Android OpenGLES如何给相机添加滤镜详解
- VmWare安装centos7无法上网的解决方法
- 如何修改CentOS服务器时间为北京时间
- linux下搭建go环境的安装配置讲解
- linux下搭建scala环境并写个简单的scala程序
- 在Linux系统下上传项目到码云的方法