网易2020校招数据分析方向提前批笔试题解析

17 篇文章 2 订阅
3 篇文章 0 订阅

网易2020校招数据分析方向提前批笔试题

选择题

  1. 有一类二叉树用三叉链表来存储的时候除了带有指向左右孩子节点的两个指针,还有指向父节点的指针,那么这样一棵二叉树有2个节点,那么有多少指针指向NULL(注:根节点的父指针指向NULL,对于不存在的节点表示为NULL)?

题解 : 4个指针 画个图可知

  1. 下列最短路径算法的叙述中正确的是(B)
    A. Dijkstra算法通常用于求每一对顶点间的最短路径;
    B. Dijkstra算法不允许图中带有负权值的边,而Floyd算法则可以适用;
    C. Floyd算法通常用于求某一顶点到其他各顶点的最短路径;
    D. Floyd算法允许有包含负权值的边组成的回路,而Dijkstra算法不允许;

题解:
A. Floyd算法通常用于求每一对顶点间的最短路径
C. Dijstra算法通常同于求某一顶点到其他个顶点的最短路径
D. Floyd算法允许包含负权值的边,但是不允许有负回路

  • 单源点的最短路径问题——Dijkstra算法
    • 将图中所有点分成 S(已求出解) 和 U(未求出解)2个点集. dist[i]表示v0到v[i]当前已求得得最短路径.A[n]为边集
    • 步骤
      • 从剩下的边集合中选出dist最短的边并将边的另一顶点vi从U中加入S.
      • 更新与vi连接的所有且并未在S中的点的dist矩阵值,dist[vk]=min(dist[vk],dist[vi]+A(i,k)).
    • 重复上述操作直到U中无与S中的点相连的点.
    • 时间复杂度:O(n2)
  • 成对的最短路径问题——Floyd算法
    • 定义:是一种在具有正或负边缘权重(但没有负周期)的加权图中找到最短路径的算法。即对于图中的每一个顶点,该算法都会找出从顶点v到v所能达到的任何其他顶点w的最短路径
    • 步骤
      • 动态规划法: Dis(i,j) =min(Dis(i,j), Dis(i,k) + Dis(k,j)).
      • for(k=0;k<n;k++){for(i=0;i<n;i++) for(j=0;j<n;j++) if(d[i][j]>(d[i][k]+d[k][j])){d[i][j]=d[i][k]+d[k][j];path[i][j]=k;}}
    • 时间复杂度:O(n3)
  1. 一个盒子中有三个大小相同的球,这三个球可能是红和蓝两种颜色,并且一个球是红的还是蓝的是等可能的。已知其中有一个是红色的,那么至少有一个球是蓝色的概率是

设P(A)为至少有一个红球的概率,P(B)为至少有一个蓝球的概率,故题设求P(B|A) = P(AB)/P(A), 其中P (A1)为一个红球都不存在的概率

至少有一个红色的概率:

P ( A ) = 1 − P ( A 1 ) = 1 − C 3 3 ( 1 / 2 ) 3 P(A)=1-P(A_1)=1-C_3^3(1/2)^3 P(A)=1P(A1)=1C33(1/2)3 = 7 / 8 7/8 7/8

在至少有一个球是红色的,另外两个球中有一个是蓝色的情况 红蓝蓝 + 红红蓝 :

P ( A B ) = C 3 1 ( 1 / 2 ) 1 ( 1 / 2 ) 2 + C 3 2 ( 1 / 2 ) 2 ( 1 / 2 1 ) = 3 / 4 P(AB) = C_3^1(1/2)^1(1/2)^2 + C^2_3(1/2)^2(1/2^1) = 3/4 P(AB)=C31(1/2)1(1/2)2+C32(1/2)2(1/21)=3/4

在至少有一个为红色的前提下,另外两个球至少有一个为蓝色的条件概率

P ( B / A ) = P ( A B ) / P ( A ) = 6 / 7 P(B/A) = P(AB)/P(A) = 6/7 P(B/A)=P(AB)/P(A)=6/7

  1. 在10件产品中有五件是残次品,从中任取五件,求其中至少有两件是残次品的概率(113/126)

P = 1 − ( C 5 1 C 5 4 + C 5 5 ) / C 10 5 ) = 113 / 226 P = 1 - (C^1_5C^4_5 + C^5_5)/C^5_{10}) = 113/226 P=1(C51C54+C55)/C105)=113/226

  1. 小明在玩掷骰子的游戏,将一颗骰子掷了两次,两次骰子的点数之和为7,求其中一次掷到6点的概率 (1/3)

两次骰子的点数之和为7的情况:1+6、2+5、3+4、6+1、5+2、4+3

其中有一次为6的情况:1+6、6+1

P = 2 / 6 P = 2/6 P=2/6

  1. 在5张卡片上按顺序写上laval这五个字母,并依次放入5个盒中,有人从中任意取出两张卡片使用,但是在放回时,忘记了两张卡片各自的位置,求此人将卡片随意放回两个空盒子后卡片顺序仍为laval的概率 ( 3/5 )

抽中相同的字符,任意放回不会改变顺序 l+l、a+a

抽中不同的字符,有1/2的几率不改变顺序

总共: C 5 2 = 10 C^2_5 = 10 C52=10种情况

P = ( 2 + 8 ∗ ( 1 / 2 ) ) / 10 = 3 / 5 P = (2 + 8*(1/2)) / 10 = 3/5 P=(2+8(1/2))/10=3/5

  1. 泊松分布概率密度函数的是(B)

在这里插入图片描述

题解:

第一个为伯努利分布

第二个为泊松分布

第三个为指数分布

第四个为均匀分布

  1. 判断一个数组或序列是正序,倒序还是乱序,需要我们将这个数组完整的遍历一遍通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应的位置并插入的排序算法是(插入排序)
  • 选择排序:每次从数组中选出一个最小数(最大数)放到数组最前面,存放在序列的起始位置,直到全部待排序的数据元素排完。

  • 希尔排序:设置增量分割数组,逐步进行直接插入排序,增量逐趟减少,并最后使得整个数组基本有序,再对整体进行直接插入排序。

  • 插入排序:构建有序序列,未排序数据依次从已排序数据按从后往前比较,插入到合适的位置。

  • 归并排序:把序列分成两个长度为n/2的子序列,对这两个子序列分别归并排序(循环将两个数组的第一个值比较,并弹出第一个值, 直到数组长度都不存在),将两个排序好的子序列合并成一个最终的排序序列

  1. 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表,进行插入操作的端称为队尾,进行删除操作的端称为队头,若用一个大小为6的数组来实现循环队列,数组下标为[0,5],且当前rear和front的值分别为0和3,当从队列中删除一个元素,再加入两个元素后,rear和front的值分别为多少?(2、4 )

顺序队列:

入队 rear += 1

出队 front += 1

队列长度 = rear - front

循环队列:

入队 rear = (rear + 1) % size

出队 front = (front + 1) % size

队列长度 = (rear - front + size) % size

  1. 访问记录visit表中包含日期date,用户user_id,访问的页面url 3个字段,以下哪个选项不能计算’2019-03-11’这一天访问过页面的所有用户数(4)
1. SELECT count(user_id) FROM (SELECT user_id FROM visit WHERE date = '2019-03-11'  GROUP BY user_id) f
2. SELECT count(user_id) FROM (SELECT DISTINCT user_id FROM visit WHERE date = '2019-03-11') f
3. SELECT count(DISTINCT user_id) FROM visit WHERE date = '2019-03-11'
4. SELECT count(user_id) FROM visit WHERE date = '2019-03-11' GROUP BY date

问题:
1.user_id 未去重
2.where 已经选出 date 在用group by 没用
correct_4. SELECT count(user_id) FROM visit WHERE date = '2019-03-11' GROUP BY user_id

简答题

  1. 用户分析是电商数据分析中重要的模块,在对用户特征深度理解和用户需求充分挖掘基础上,进行全生命周期的运营管理(拉新—>活跃—>留存—>价值提升—>忠诚),请尝试回答以下3个问题:

    1. 用户第一单购买的行为往往反映了用户对平台的信任度和消费能力。现在数据库中有一张用户交易表order,其中有userid(用户ID)、amount(消费金额)、paytime(支付时间),请写出对应的SQL语句,查出每个用户第一单的消费金额。
      select userid,amount 
      from order where userid in(
          select userid, min(paytime)
          from order 
          group by userid
      )
    
    1. 当你发现本月的支付用户数环比上月大幅下跌(超30%),你会如何去探查背后的原因?请描述你的思路和其中涉及的关键指标

    本小题主要考查用户流失分析的基本思路:
    用户流失该如何分析
    如何进行用户流失原因调研?

    1. 两层模型:细分用户、产品、渠道,看到底是哪里用户流失了。注意由于是用户流失问题,所以这里细分用户时可以细分用户处在生命周期的哪个阶段。
    2. 指标拆解:用户流失数量 = 该群体用户数量*流失率。拆解,看是因为到了这个阶段的用户数量多了(比如说大部分用户到了衰退期),还是这个用户群体的流失率比较高内外部分析:
      a. 内部:新手上手难度大、收费不合理、产品服务出现重大问题、活动质量低、缺少留存手段、用户参与度低等
      b. 外部:市场、竞争对手、社会环境、节假日等
    1. 为了更好的理解用户,我们通常会基于用户的特征对用户进行分类,便于更加精细化的理解用户,设计产品和运营玩法,请你设计对应的聚类方法,包括重点的用户特征的选择及聚类算法并说明其基本原理和步骤

    本小题主要考查用户分类

    1. 采用RFM用户价值模型确定用户特征
      R:最近一次消费(recency),代表用户距离当前最后一次消费的时间,当然是最近一次消费的时间距今越短越好,对我们来说更有价值,更可能有效的去触达他们。
      F:消费频次(frequency),用户在一段时间内,在产品内的消费频次,重点是我们对一段时间的定义。
      M:消费金额(monetary),代表用户的价值贡献

    2. 聚类方法
      知识点:用户分析六大方法论

      对于连续数据且数据量较大的数据,用Kmeans聚类法。基本原理:先随机选取K个对象作为初始的聚类中心,然后计算每个对象与各种子聚类中心之间的距离,把每个对象分配给他最近的聚类中心。一旦全部对象被分配了,每个聚类的聚类中心会根据聚类中现有的对象被重新计算。这个过程将不断重复直至满足某个终止条件。

      • 用Python实现Kmeans的步骤:
        1. 导入pandas,numpy,matplotlib等包,用read_csv/table等导入数据
        2. 数据预处理,用astype方法做类型转换;用duplicated方法加any方法识别冗余数据、并用drop duplicated清除冗余数据;用Python的isnull方法识别缺失值,并选用删除法/插补法/替补法等处理。
        3. 用dist()函数定义距离并计算,一般使用欧式距离
        4. 先用scatter()作数据散点图,根据散点图设定K值,用np.random,randint随机获得中心点
        5. 迭代,用while循环,一般需要设置最大迭代次数
        6. 用matplotlib.subplots()作图
  2. 网易严选是网易旗下原创生活类自营电商品牌,深度贯彻“好的生活,没那么贵”的品牌理念。商品覆盖居家、餐厨、配件、服装、洗护、母婴、原生态饮食等几大类目,兼具品质和性价比,得到用户的广泛好评。若你是网易严选负责商品的数据分析师,当面对以下业务问题时,你会如何解决?

    1. 用户增长团队期望选择一批合适的商品用于吸引新客,期望你帮助从数据的角度筛选出一批合适的商品,你会如何帮助他们进行筛选?请描述你的思路。

题解:本小题主要考查精准营销

  • 精准营销的五个方面:在合适的时间、合适的地点、将合适的产品以合适的方式提供给合适的人
  1. 确定目标客户。如母婴产品,最主要的目标客户孕妇或者一些准爸爸;
  2. 获取最佳潜客的数据源;
  3. 通过数据发掘确认潜客的“前期征兆”;如孕妇前期可能会购买防辐射服
  4. 制定获得顾客的流程;
  5. 采用KPI(关键指标)测试并不断修正获客流程。

参考文献:

  1. 用大数据方法获得新顾客
  2. 如何通过数据分析达到精准营销的目的?
  1. 商品研发负责人期望能有一套指标帮助衡量开发的商品表现,请你帮助设计对应的评估方案,包括设计思路、涉及的数据指标等。

衡量商品表现的指标体系建立:参考文章
1、产品规模:
(1)基于用户属性拆分为:日(月)新增、日(月)回流、日(月)持续活跃,也可以用日(月)新增、日(月)回流、日(月)持续活跃来预测日活/月活,作为制定目标的依据。
(2)基于商业属性可以拆分为:日(月)付费用户、日(月)非付费用户
2、用户健康度:
(1)产品基础指标,主要评价产品本身的运行状态:PV、UV、新用户数;
(2)流量质量指标,主要评价用户流量的质量高低:跳出率、人均浏览次数、人均停留时间、用户留存率、用户回访率;
(3)产品营收指标,主要评价产品的盈利能力与可持续性:用户支付金额(GMV)、客单价(ARPU)、订单转化率;
3、产品质量:crash率、启动耗时、页面加载速度等,视频播放产品还会有播放成功率、播放加载速度等;产品的下载:安装率、卸载率、push关闭率也是关注指标。
4、用户属性(用户画像):
(1)人口属性:包括性别、年龄等人的基本信息;
(2)兴趣特征:浏览内容、收藏内容、阅读咨询、购买物品偏好等;
(3)位置特征:用户所处城市、所处居住区域、用户移动轨迹等;
(4)设备属性:使用的终端特征等;
(5)行为数据:访问时间、浏览路径等用户在网站的行为日志数据;
(6)社交数据:用户社交相关数据;

编程题

	题目:
	小易在维护数据的时候遇到一个需求,具体来说小易有一系列数据,这些数据了构成一个长度为n的数字序列,接下来小易会在这个序列上进行q次操作。每次操作有一个查询的数字x,小易需要将序列数据中所有大于等于x的数字都减一,并输出在本次操作中有多少个数字被减一了。小易犯了难,希望你能帮帮他。
	
	输入描述:
	第一行n,q,表示数字个数和操作个数。 
	接下来一行n个数表示初始的数字。 
	接下来q行,每行一个数,表示指定的数字x。
	1 <= n,q <= 200000,1 <= ai,x <= n
	  
	输出描述:
	对于每个查询,输出一个数字表示答案
	
	输入例子1:
	4 3
	1 2 3 4
	4
	3
	1
	输出例子1:
	1
	2
	4
	
	输入例子2:
	3 2
	1 2 3
	3
	3
	输出例子:
	1
	0
	
	  
	题解:
	  1. 每次查询一个数字x,使得大于等于x的数字都会-1,那么数列还是有序的。也就是数列始终都是有序的
	  2. 排序后找就可以
      
	#include <stdio.h>
	#include <iostream>
	#include <vector>
	#include <algorithm>
	using namespace std;
	int main()
	{
	    vector<int> nums;
	    int m,n;
	    cin>>m>>n;
	    for(int i = 0;i < m; i++){
	        int x ; cin>>x;
	        nums.push_back(x);
	    }
	    sort(nums.begin(),nums.end(),greater<int>());
	    while(n--){
	        int x,ans = 0; cin>>x;
	        for (int i = 0; i < nums.size(); i++){
	            if (nums[i] >= x){
	                nums[i] -= 1;
	                ans ++ ;
	            }else{
	                break;
	            }
	        }
	        cout<<ans<<endl;
	    }
	    return 0;
	}
'''
	题目:
	小易学习了辗转相除法之后,就开始实践这个算法在求解最大公约数上。
	牛牛给小易出了一道不同寻常的求解最大公约数: 求解a和b的最大公约数,但是a和b的范围特别大。
	小易遇到了困难,向聪明的你寻求帮助,希望你能帮帮他。
	
	输入描述:
	第一行数字a,第二行数字b
	1 <= a <= 10^(10^5), 1 <= b <= 10^18
	
	输出描述:
	一行一个数字表示答案
	
	输入例子1:
	6
	4
	输出例子1:
	2
	
	输入例子2:
	7951346523609888
	6998915114363550
	输出例子2:
	1013754
	
	题解:
	辗转相除法
	'''
	
	def fun(x,y):
	    a = max(x,y)
	    b = min(x,y)
	    if a%b == 0:
	        return b
	    else:
	    		return fun(b, a%b)
	if __name__ == '__main__':
	    x = int(input())
	    y = int(input())
	    print(fun(x,y))
	题目:
	小易有一个初始为空的数字集合,支持两种操作:
	1、加入数字x到集合中。
	2、询问集合中是否存在一个子集,满足子集中所有数字的Or值恰好为k。
	Or为二进制按位或操作,C++中表示为"|"。
	
	输入描述:
	第一行数字q,表示操作个数 
	接下来q行,每行两个数字: 
	1 x 表示插入数字x 
	2 x 表示询问数字x(即题设中询问的数值k)
	
	输出描述:
	对于每个询问,输出"YES"或者"NO"表示是否存在。
	
	输入例子1:
	9
	1 4
	2 5
	1 9
	1 15
	2 4
	1 11
	2 10
	2 7
	2 9
	
	输出例子1:
	NO
	YES
	NO
	NO
	YES
	
	题解:
	1. 题目要求是否存在没说 哪个子集满足
	2. 这些子集需要满足的条件: 和 x 与一下等于x
	3. 用临时数字记录 这些能和x与一下 x不变的数字
	4. 最后判断 临时数组和x是否一样
	
	#include <stdio.h>
	#include <iostream>
	#include <vector>
	using namespace std;
	int main()
	{
	    vector<int> nums;
	    bool visit[100010]={0};
	    int m;cin >> m;
	    while(m--){
	        int x,y;
	        cin>>x>>y;
	        if(x == 1 && visit[y] == false){
	            nums.push_back(y);
	            visit[y] = true;
	        }else if (x == 2){
	            int tmp  = 0;
	            for(int i = 0;i < nums.size();i++){
	                if((nums[i] | y) == y)
	                    tmp |= nums[i];
	            }
	            if(tmp == y)
	                cout<<"YES"<<endl;
	            else
	                cout<<"NO"<<endl;
	        }
	    }
	    return 0;
	}
	题目:
	小易给定了一个长度为n的数字序列,对于每一个1<=k<=n,小易希望能求解出所有长度为k的连续子序列的最大值中的最小值。
	
	输入描述:
	第一行数字n 
	接下来一行是一个长度为n的数字序列
	1<=n<=100000,0<=ai<=10^9
	
	输出描述:
	一行n个数字,第i个数字表示k = i时的答案
	
	示例1输入:
	6
	1 3 2 4 6 5
	
	示例1输出:
	1 3 3 4 6 6
	
	示例1说明:
	当k = 2的时候
	子序列分别是:
	1 3 最大值为 3
	3 2 最大值为 3
	2 4 最大值为 4
	4 6 最大值为 6
	6 5 最大值为 6
	所有最大值中的最小值为3
	
	
	#include <iostream>
	#include <algorithm>
	#include <unordered_map>
	#include <vector>
	#include <stack>
	
	using namespace std;
	const int N = 3000010;
	int V[N];
	int main(){
	    int n;
	    cin>>n;
	    for(int i = 0;i < n;++ i) scanf("%d",&V[i]);
	    vector<int> L(n,-1); //左边第一个比下标对应的数大的数离该下标的长度
	    vector<int> R(n,-1); //右边第一个比下标对应的数大的数离该下标的长度
	    //单调栈生产L和R数组信息
	    stack<int> S;
	    for(int i = 0;i < n;++ i){
	        while(!S.empty()&&V[S.top()]<V[i]){
	            int t = S.top();
	            R[t] = i - t;
	            S.pop();
	        }
	        S.push(i);
	    }
	    stack<int> S2;
	    for(int i = n-1;i >= 0;-- i){
	        while(!S2.empty()&&V[S2.top()]<V[i]){
	            int t = S2.top();
	            L[t] = t - i;
	            S2.pop();
	        }
	        S2.push(i);
	    }
	    vector<int> last(n,-1); //last[i]表示,在第i个位置,以V[i]为最大值的最大窗口的长度
	    for(int i = 0;i < n;++ i){
	        int left = 0,right = 0;
	        left = L[i] == -1? i + 1 : L[i];
	        right = R[i] == -1? n - i : R[i];
	        last[i] = left + right - 1;
	    }
	    vector<int> res(n+2,1e9);//res[k]代表长度为k的窗口能取到的最大值
	
	    /**************************************************************************
	    生成答案算法:
	    对于每一个V[i]用其能达到的最大长度last[i],去更新所对应的res[last[i]]:
	    res[last[i]] = min(res[last[i]],V[i]);
	    最后,将res数组中,没有更新到的数进行补齐,res[k]跟新就是从k开始,找一个
	    已经更新过的res[i],遇到的第一个res[i]就是res[k]的值,所以:
	    res[i] = min(res[i],res[i+1]);
	    **************************************************************************/
	    for(int i = 0;i < n;i ++){
	        res[last[i]] = min(V[i],res[last[i]]);
	    }
	    for(int i = n;i;i --){
	        res[i] = min(res[i],res[i+1]);
	    }
	    for(int i = 1;i <= n;++ i) printf("%d ",res[i]);
	    return 0;
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值