为了OFFER系列 | 牛客网美团点评数据分析刷题

举报
毛利 发表于 2021/07/15 02:22:42 2021/07/15
【摘要】 @Author:Runsen 对于大学的每一个阶段,都有着不同的意义,在大学期间一定要有明确的战略、打法,以及人生布局,才能最大程度的提升自己,才能在未来走的更远。 现如今大四,为了OFFER,冲啊 下面题目都是来自美团点评的2020春招的数据分析原题。 文章目录 1、数据分析思维2、数据库3、数学题4、编程题5、编程题6、编程题7、关联查询8、编程...

@Author:Runsen

对于大学的每一个阶段,都有着不同的意义,在大学期间一定要有明确的战略、打法,以及人生布局,才能最大程度的提升自己,才能在未来走的更远。

现如今大四,为了OFFER,冲啊

下面题目都是来自美团点评的2020春招的数据分析原题。

1、数据分析思维

广告是互联网企业重要的变现模式,在美团的广告业务中,商家会和美团的销售签订不同类型的广告合同(比如,按点击收费的广告cpc、按曝光收费的广告cpm、按时长收费的广告cpt)。美团会为商家创建相关的广告内容素材创意(比如,门店图片、活动图片、促销文字等),并通过美团的广告引擎,根据用户访问的行为特征,基于算法策略将商家的广告内容投放到美团的app或者外部合作伙伴(比如如:腾讯,头条)的app不同的展示位置上。普通用户访问这些广告后,会对商家产生兴趣,可能产生购买转换行为,美团会和商家做广告的计费结算,同时为商户提供用户的广告效果信息(比如:广告带来的门店访问量、订单数等)。

1、 如果让你对这个业务进行抽象,你会抽象出哪些数据分析主题,并说出你这样分的原因;

2、 请你根据问题1抽象的主题,进行主题模型设计,并说明设计的模型内容,以及模型之间的关系。

1、 广告素材特点和用户访问量的主题:用来分析不同特点和素材的广告对吸引用户访问是否有较大的关系。
用户访问行为特征和最终购买行为主题:分析用户在广告页面滑动、点击、停留等特征,是否对最终购买行为有较大的关系。
收费模式、商户类型、商户付费的关系:分析不同类型的商户在不同模式下的付费意愿,用于向未使用广告业务的商户推广
投放时段和访问量订单数的关系:能带来高访问量或订单数的投放时段,价格可以适当调整
不同类型商户广告投放的效果分析:分析哪些类型商户广告投放效果较差,可以帮助商户调整引流策略

2、 用户访问行为特征和最终购买行为主题:特征值可以选择用户点击进入广告后的行为特征,包括滑动速度、滑动方向、停留时间、点击等。
结合最终购买行为,用来分析用户行为特征对购买行为的影响。可以实时预测用户行为是否有较大几率产生购买行为。对购买意愿弱的用户,可以在页面中实施其他推广营销策略,加强用户的购买意愿。

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2、数据库

说明关系型数据库通过索引提升查询效率的背后原理 。

1. 如果没有索引,数据库引擎需要通过全表扫描来查找数据,这会产生大量的磁盘IO。

2. 关系型数据库使用B+树构建索引来加速加快查询。B+树是一种二叉查找树(每个节点的键值必须:比保存在左子树的任何键值都要大,比保存在右子树的任何键值都要小),这样随机查找某个键值时可以通过从根节点执行二叉查找来加速查询,查询成本取决于树的层数。

3. 针对范围查询和排序的优化:在每个叶子节点保存其下一个叶子节点的指针,这样当指定范围范围查询时,先从根节点根据范围的左值找到其叶子节点,之后通过向后遍历叶子节点即可找到对应范围右值,这样可以加速范围查询、排序、分组等数据库查询动作。

4. 针对磁盘读写速度的优化:除了叶子节点之外的其他节点只保存键值,这样对磁盘的单次读写可以获取到尽可能多的数据。以MySQL为例,一个1000万行的表对应的B+树按照主键查找理论上只需要3次磁盘IO,这相对于全表扫描带来的磁盘IO是多个量级的性能提升。

5. MySQL等数据库引擎在实际实现B+树索引的时候,针对磁盘读写做了优化:非叶子节点中只存放key值,叶子节点中除了key值也会存放数据,按照存放数据的不同索引区分为主索引(聚簇索引)和辅助索引:

a) 主索引的叶子节点中存放该key值对应的完整记录,使用主索引进行查找时,可以直接输出记录;一个表只能创建一个主索引。

b) 普通索引的叶子节点则存放对应主键的值,因此在使用辅助索引进行查找时,需要先查找到主键值,然后再到主索引中进行查找;一个表可以创建多个辅助索引。

6. 除了B+树,关系型数据库一般也支持哈希索引,哈希索引能够非常高效地进行随机查找,但是对于范围查询、排序和分组都不支持。

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

3、数学题

【污水处理问题】一家污水处理厂通过去掉污水中有害的污物来净化水质,生产出用于灌溉使用的水源。该处理过程每小时可以去掉处理池中剩余污物的12%。

问:1.一天后处理池中将大概处理掉百分之几的污物?

2.要多长时间才能把污物的量减少一半?

设:初始污物量= a 0 a_0 a0、处理x小时后的污物量= a x a_x ax

于是得到污水处理模型: a x + 1 = a x − a x ∗ 12 % = 0.88 a x a_x+1=a_x-a_x*12\%=0.88a_x ax+1=axax12%=0.88ax,转化为基础表达式为 a x = ( 0.88 ) ∗ a 0 a_x=(0.88) * a_0 ax=(0.88)a0,其中x为污水处理的小时数

  1. 一天为24小时,即 a 24 = ( 0.88 ) 24 ∗ a 0 ≈ 0.0465 ∗ a 0 a_{24}=(0.88)^{24}*a_0≈0.0465*a_0 a24=(0.88)24a00.0465a0,即一天后大于处理掉95.35%的污物;

  2. 处理掉一半,即 a x = 0.5 ∗ a 0 a_x=0.5*a_0 ax=0.5a0 0.5 = ( 0.88 ) x 0.5=(0.88)^x 0.5=(0.88)x x = l o g 0.5 / l o g 0.88 ≈ 5.42 x=log0.5/log0.88≈5.42 x=log0.5/log0.885.42小时;

4、编程题

在4*4的棋盘上摆满了黑白棋子,黑白两色的位置和数目随机其中左上角坐标为(1,1),右下角坐标为(4,4),现在依次有一些翻转操作,要对一些给定支点坐标为中心的上下左右四个棋子的颜色进行翻转,请计算出翻转后的棋盘颜色。

(1)输入描述:
给定两个数组,分两行
第一行为分别为初始棋盘,为 4 ∗ 4 4∗4 44矩阵,其中0表示白色棋子,1表示黑色棋子
第二行为翻转位置,其中翻转位置共有3个
(2)输出描述:请返回翻转后的棋盘,为 4 ∗ 4 4∗4 44矩阵
(3)输入例子:

[[0,0,1,1],[1,0,1,0],[0,1,1,0],[0,0,1,0]]
[[2,2],[3,3],[4,4]]

  
 
  • 1
  • 2

(4)输出例子:

[[0,1,1,1],[0,0,1,0],[0,1,1,0],[0,0,1,0]]

  
 
  • 1

思路: 将支点的前后左右都进行翻转,需要明确支点的位置,就是对支点的位置进行判断,如果存在就翻转,这里的翻转可以直接用1-color,具体代码如下所示。

'''
@Author: Runsen
@微信公众号: 润森笔记
@博客: https://blog.csdn.net/weixin_44510615
@Date: 2020/8/30
'''
# 将支点的前后左右都进行翻转,但是需要明确支点的位置
def doFilp(array,position): for x, y in position: # 对index进行减一操作 x -=1 y -=1 # 支点左边还有棋子,那么就进行翻转 if x > 0: array[x-1][y] = 1-array[x-1][y] # 支点右边还有棋子,那么就进行翻转 if x < 3: array[x+1][y] = 1- array[x+1][y] # 支点下边还有棋子,那么就进行翻转 if y > 0: array[x][y-1] = 1 - array[x ][y-1] # 支点上边还有棋子,那么就进行翻转 if y < 3: array[x][y+1] = 1 - array[x ][y+1] return array

if __name__ == '__main__': array = eval(input()) position = eval(input()) print(doFilp(array,position))

# 测试成功
[[0,0,1,1],[1,0,1,0],[0,1,1,0],[0,0,1,0]]
[[2,2],[3,3],[4,4]]
[[0, 1, 1, 1], [0, 0, 1, 0], [0, 1, 1, 0], [0, 0, 1, 0]]


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

5、编程题

寻找最后的山峰。山峰元素是指其值大于或等于左右相邻值的元素。给定一个输入数组 n u m s nums nums,任意两个相邻元素值不相等,数组可能包含多个山峰。找到索引最大的那个山峰元素并返回其索引。 假设 n u m s [ − 1 ] = n u m s [ n ] = − ∞ nums[-1] = nums[n] = -∞ nums[1]=nums[n]=
(1)输入描述:在命令行中输入一行数字,数字之间以空格分割,遇到换行符结束。输入的数字为整型,且总数量在10万以内。
(2)输出描述:输出索引最大的山峰的索引值(一个数字)
(3)输入例子:2 4 1 2 7 8 4
(4)输出例子:5

'''
@Author: Runsen
@微信公众号: 润森笔记
@博客: https://blog.csdn.net/weixin_44510615
@Date: 2020/8/30

在命令行中输入一行数字,数字之间以空格分割,遇到换行符结束。输入的数字为整型,且总数量在10万以内。
输出索引最大的山峰的索引值(一个数字)
'''
# 判断是不是山峰,就是左边小,右边大
def peakindex(nums): nums.insert(0, float('-inf')) nums.append(float('-inf')) result = [] for i in range(1,len(nums) -1): if nums[i-1] < nums[i] and nums[i] > nums[i+1]: result.append(i-1) return max(result)
if __name__ == '__main__': # 将一行数字字符串,转化为列表整数类型。 s = input().strip(' ').split(' ') nums = [int(i) for i in s] print(peakindex(nums))


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

6、编程题


给定一个整数数组,返回一个数组。该返回数组中第i个数字为,原数组中第i个位置的数字至少往右走多少步才能遇到比它大的数字。如果遇不到或者已经处于最右的位置,则置为-1。

输入描述::输入为多行,第一行为一个整数N,1≤N≤106

接下来一共有N行,每一行为一个整数M,0≤M≤232-1

输出描述::输出 N 行,每行一个数字表示转换之后的数组

输入例子1:

5
91
10
3
22
40

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

输出例子1:

-1
2
1
1
-1

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

思路:栈方法

'''
@Author: Runsen
@WeChat:RunsenLiu 
@微信公众号: Python之王
@CSDN: https://blog.csdn.net/weixin_44510615
@Github: https://github.com/MaoliRUNsen
@Date: 2020/8/31
'''
def solution(nums): result = [-1] * N stack = [] # 倒序遍历 for i in range(N - 1, -1, -1): # stack存放着倒序的index。然后用对应的index相减 # 判断栈是否为空和 nums中的前面的数字是不是比后面的大 while len(stack) > 0 and nums[i] >= nums[stack[-1]]: stack.pop() # stack最后一个就是 i 变大的index if len(stack) > 0: result[i] = stack[-1] - i else: # 不存在说明后面没有比i 大的数 result[i] = -1 stack.append(i) return result
if __name__ == '__main__': N = int(input()) nums = [int(input().strip()) for _ in range(N)] result = solution(nums) for i in result: print(i)


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

7、关联查询

数据对象data1List,员工表,存储员工ID,员工姓名

数据对象data2List, 员工工作时长表,存储员工ID,月份,工时

计算每个员工1-3月每月工时及总工时

输入描述:

员工ID 员工姓名

员工ID 月份 工时 月份 工时 月份 工时

  
 
  • 1
  • 2
  • 3

输出描述:

员工姓名 空格 一月份工时 空格 二月份工时 空格 三月份工时 空格 总工时

  
 
  • 1

输入例子1:

zhangwei01
01 200 02 150 03 196

  
 
  • 1
  • 2

输出例子1:

zhangwei01 200 150 196 546

  
 
  • 1

难度简单。不说了,就是送分。

data1List=input().strip().split(" ")
data2List=input().strip().split(" ")
print(data1List[1]+" "+data2List[2]+" "+data2List[4]+" "+ data2List[6]+" "+str(int(data2List[2])+int(data2List[4])+int(data2List[6])))

  
 
  • 1
  • 2
  • 3
  • 4

8、编程题

在实时计算中,数据流源源不断地流入计算单元,经常需要借助窗口来处理数据,其中有一类窗口为滑动窗口(Sliding Window),其特点是窗口长度固定,每次滑动一定的位移(slide)

现给定一个数组 nums,有一个长度为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。注意你只可以看到在滑动窗口 k 内的数字,滑动位移大小slide=1,即滑动窗口每次只向右移动一位。

要求返回每一个滑动窗口内的中位数,解释中位数定义,例如:对于[2,3,4],中位数是3;对于[2,3],中位数是 (2 + 3) / 2 = 2.5

注意:为了简化窗口计算,规定如果没有累计到窗口大小的数,不能触发计算,即不输出结果!

输入描述:

输入两个数字n,k。n表示数组长度,k表示窗口大小

加下来n个整数用空格隔开,表示nums数组

(1<=k<=n)

(1<=n<=1000)

  
 
  • 1
  • 2
  • 3

输出描述:

输出若干个数字,表示滑窗依次移动得到的结果,保留小数点后一位数字

输入
8 3
1 3 -1 -3 5 3 6 7
输出
1.0 -1.0 -1.0 3.0 5.0 6.0

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

说明

'''
@Author: Runsen
@WeChat:RunsenLiu 
@微信公众号: Python之王
@CSDN: https://blog.csdn.net/weixin_44510615
@Github: https://github.com/MaoliRUNsen
@Date: 2020/8/31
'''
n,k = map(int,input().strip().split())
nums = list(map(float,input().strip().split()))
res = []
mid = k // 2
# 滑动窗口的次数
for i in range(len(nums)-k+1): cur = sorted(nums[i:i+k]) #  奇数 if k % 2 != 0: res.append(round(cur[mid],2)) else: res.append(round((cur[mid] + cur[mid-1]) / 2,2))
res = [str(i) for i in res]
print(' '.join(res))


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

9、编程题

输入年份月份,请输出这个月的天数

输入描述:多组输入输出

第一个参数为年份,如2018代表2018年,2019代表2019年
第二个参数为月份,如1代表1月,2代表2月

输出描述:输出当月的实际天数。

示例1
输入
2018 2
2020 2
2019 1
输出
28
29
31

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

难度简单。不说了,就是送分。

def solution(a,b): if b != 2: if b in [1,3,5,7,8,10,12]: return 31 else: return 30 else: # 判断是不是闰年 if a % 100 != 0 and a % 4 ==0: return 29 elif a % 400 == 0: return 29 else: return 28


while True: try: year, month = map(lambda x:int(x),input().split(' ')) print(solution(year, month)) except: break

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

10、编程题

整数分解:一个正整数N可以分解为 M ( M > 1 ) M(M>1) M(M>1)个正整数的和,即 N = K + L N=K+L N=K+L,例如 N = 5 N=5 N=5 M = 2 M=2 M=2时可以分解为 ( 1 + 4 , 2 + 3 ) (1+4,2+3) (1+4,2+3)
给定一个正整数 N ( 1 < N < 200 ) N(1<N<200) N(1<N<200)及正整数 M ( 1 < M < 200 ) M(1<M<200) M(1<M<200),求有多少种可能的分解组合(注:K+L和L+K算一种)

示例1
输入
5,2
输出
2

# 递归
def solution(N, M): # 实际上就是N个球装到M个杯子里,要求每个杯子都要有球,有多少种装法。 if (M == 1) or (N - M == 1) or (N == M): dic[(N, M)] = 1 elif M == 2: dic[(N, M)] = int(N / 2) else: left, i, total = N - M, 1, 0 while left >= i and i <= M: if (left, i) in dic.keys(): total = total + dic[(left, i)] i = i + 1 else: solution(left, i) dic[(N, M)] = total


if __name__ == '__main__': N, M = map(int, input().split(",")) dic = {} solution(N, M) print(dic[(N,M)])


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

如果你想跟博主建立亲密关系,可以关注博主,或者关注博主公众号“Python之王”,了解一个非本科程序员是如何成长的。
博主ID:润森,希望大家点赞、评论、收藏

文章来源: maoli.blog.csdn.net,作者:刘润森!,版权归原作者所有,如需转载,请联系作者。

原文链接:maoli.blog.csdn.net/article/details/108312920

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。