天天看点

数据仓库高级工程师 字节跳动面试

本人面试的是 数据仓库高级工程师–推荐系统,从官网投的校招,2020年底最后一天发的简历,元旦假三天,四号早上来了通知

以下是面试题,希望有帮助

1.自我介绍

挑重点,与面试职位无关的经历不要说,除非特别牛逼那最多一两句(托福雅思三外比赛创业国际代表),年级学校专业目标,本科做过什么科研立项什么项目,在实验室学习什么方向,自我介绍完了会让你详细说某一个做过的项目,然后细问。

2.spark与mapreduce

Spark 是一种与 Hadoop 相似的开源集群计算环境,但是两者之间还存在一些不同之处,这些有用的不同之处使 Spark 在某些工作负载方面表现得更加优越,换句话说,Spark 启用了内存分布数据集,除了能够提供交互式查询外,它还可以优化迭代工作负载。Spark 在 Scala 语言中实现,它将 Scala 用作其应用程序框架。与 Hadoop 不同,Spark 和 Scala 能够紧密集成,其中的 Scala 可以像操作本地集合对象一样轻松地操作分布式数据集。尽管创建 Spark 是为了支持分布式数据集上的迭代作业,但是实际上它是对 Hadoop 的补充,可以在 Hadoop 文件系统中并行运行。通过名为 Mesos 的第三方集群框架可以支持此行为。Spark 由加州大学伯克利分校 AMP 实验室 (Algorithms, Machines, and People Lab) 开发,可用来构建大型的、低延迟的数据分析应用程序。

MapReduce是一种编程模型,用于大规模数据集(大于1TB)的并行运算。概念"Map(映射)“和"Reduce(归约)”,是它们的主要思想,都是从函数式编程语言里借来的,还有从矢量编程语言里借来的特性。它极大地方便了编程人员在不会分布式并行编程的情况下,将自己的程序运行在分布式系统上。 当前的软件实现是指定一个Map(映射)函数,用来把一组键值对映射成一组新的键值对,指定并发的Reduce(归约)函数,用来保证所有映射的键值对中的每一个共享相同的键组。

3.jvm

JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。

4.hashmap

基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。(除了非同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。 此实现假定哈希函数将元素适当地分布在各桶之间,可为基本操作(get 和 put)提供稳定的性能。迭代 collection 视图所需的时间与 HashMap 实例的“容量”(桶的数量)及其大小(键-值映射关系数)成比例。所以,如果迭代性能很重要,则不要将初始容量设置得太高(或将加载因子设置得太低)。

hashmap的重写方法

import java.util.*;
public class Exp2 {
    public static void main(String[] args) {
        HashMap h2 = new HashMap();
        for (int i = 0; i < 10; i++) {
            h2.put(new Element(i), new Figureout());
            System.out.println("h2:");
            System.out.println("Get the result for Element:");
        }
        Element test = new Element(3);
        if (h2.containsKey(test)) {System.out.println((Figureout) h2.get(test));} 
        else {
            System.out.println("Not found");
        }
}
   static class Element {
        int number;
        public Element(int n) {
            number = n;
            }
}
    static class Figureout {
    Random r = new Random();
    boolean possible = r.nextDouble() > 0.5;
    public String toString() {
    if (possible) {
    return "OK!";
    } else {
    return "Impossible!";
    }
    }
}
}
           

5.线程与进程的关系(这题应该不是原本要问的毕竟太简单)

6.代码题:单链表去重(问设计思路、复杂度,以及要写出来运行,语言可以选)这题之前会问你熟悉的语言是什么

输入1 2 2 3 3 3 4

输出1 4

#include <stdio.h>
#include <stdlib.h>
 
/******************************************************************
*[email protected]														  *
*[email protected]												  *
*[email protected] linked list deduplication					  		  *
*******************************************************************/ 
 
/**自定义数据类型**/ 
typedef char Datatype; 
 
/**声明结构体**/
struct Node
{
	Datatype data;
	struct Node *next;
};
 
/**结构体定义**/
typedef struct Node SNode;  //结点 
typedef struct Node* SLinkNode;  //指针 
 
/**单链表初始化**/
 void InitSList(SLinkNode *head)
{
 	if((*head=(SLinkNode)malloc(sizeof(SNode)))==NULL)	
 	{
		exit(-1);  	
	}
	(*head)->next=NULL;
} 
 
/**单链表插入元素**/
int InsertSList(SLinkNode head,int i,int elem)
{
	SNode *pnew,*p;	
	p=head;
	int j=0;
	while(p->next!=NULL && j<i-1)
	{
		p=p->next;
		j++;
	}
	if(j!=i-1)
	{
		printf("插入位置错误!");
		return 0;
	}
	pnew=(SNode*)malloc(sizeof(SNode));
	pnew->data=elem; 
	pnew->next=p->next;
	p->next=pnew;
	return 1;
} 
 
/**核心--单链表元素去重**/
void DistinctElem(SLinkNode head)
{
	SNode *p,*mark,*q;
	for(mark=head->next;mark!=NULL;mark=mark->next)
	{
		q=mark;
		p=mark->next; 
		while(p)
		{		
			if(mark->data==p->data)
			{
				q->next=p->next; 
				free(p);	
				p=q->next;				
			}else
			{
				q=p;
				p=p->next;
			}
		}
	}
}
 
 
 
int main()
{
	char arr[]={'A','B','A','E','B','E','A'}; 
	SLinkNode list1;
	
	//初始化带有头节点list1单链表 
	InitSList(&list1); 
	
	//插入元素 
	int i=1;
	for(i;i<=sizeof(arr)/sizeof(char);i++)  
	{
		if(InsertSList(list1,i,arr[i-1])==0) 
		{
			printf("插入失败!");
			return; 
		}
	}
	
	//输出单链表 
	SNode *p=list1;
	while(p->next != NULL)  
	{   
		p=p->next;
		printf("%c ",p->data); 
	}
	printf("\n"); 
	
	 //单链表去重 
	DistinctElem(list1); 
	
	//输出单链表 
	SNode *p1=list1;
	while(p1->next != NULL)  
	{   
		p1=p1->next;
		printf("%c ",p1->data); 
	}
	printf("\n"); 
	
	return 0;
}
           
Node* List::deleteDuplication()			    
{
	
	int n[100];	
	int i=0;
	int times=0;
	Node *temp=m_pList;                         //头节点
	if(!m_pList)  return NULL;
	while(temp->next!=NULL)                    //第一次遍历存数据
	{
		n[i++]= temp->data;
	//	if(temp->next!=NULL)
		 temp=temp->next;
	}
	n[i++]= temp->data;                        //注意尾节点数据不要丢失
//	for(int j=0;j<i;j++)					  //这三行调试用
//	 cout <<n[j];
//	cout<<endl;
	temp=m_pList;                              //再次指向头节点
	while(temp->next!=NULL)                    //再遍历去重
	{
		times++;                               //记录位置
		Node * tempbefore = temp;
		temp=temp->next;                       //循环向后
		for(int k=0;k<times;k++)			   //这段代码是链表去重 
		{
			if(temp->data == n[k])
			{
				Node * newtemp = temp->next;
				tempbefore->next=newtemp;
				newtemp=NULL;
				m_iLength--;
				temp=tempbefore;            //删掉后不要往后指会遗漏
				break;
			}
		}
	}
	return m_pList;		
}


Node* List::deleteDuplication()				   //重复的都删掉 
{
	
	int n[100],m[100];	
	int i=0;
	int times=0;
	Node *temp=m_pList;
	if(!m_pList)  return NULL;
	while(temp->next!=NULL)
	{
		n[i++]= temp->data;
		 temp=temp->next;
	}
	n[i++]= temp->data;
	i=0;
	temp=m_pList;
	while(temp->next!=NULL)
	{
		times++;
		Node * tempbefore = temp;
		temp=temp->next;
		for(int k=0;k<times;k++)
		{
			if(temp->data == n[k])
			{
				m[i++]=temp->data;
				Node * newtemp = temp->next;
				tempbefore->next=newtemp;
				newtemp=NULL;
				m_iLength--;
				temp=tempbefore;
				break;
			}
		}
	}
	for(int j=0;j<i;j++)	
		{	
			temp=m_pList;	               //再来一轮,把重复出现都删掉
		while(temp->next !=NULL)
			{
			Node * tempbefore = temp;
			temp=temp->next;
			if(temp->data == m[j])
			{
				Node * newtemp = temp->next;
				tempbefore->next=newtemp;
				newtemp=NULL;
				m_iLength--;
				temp=tempbefore;				
			}
	
	   	 } 
	}	
		for(int j=0;j<i;j++)
		{
			if(m_pList->data == m[j])
			{
				Node *newhead=m_pList->next;
				return newhead;
			}
		}
		
	return m_pList;		
}


           

验证

#include<iostream>
#include"List.h" 
using namespace std;

int main(void)
{
	Node node1;
	node1.data=1;
	Node node2;
	node2.data=1;
	Node node3;
	node3.data=2;
	Node node4;
	node4.data=2;
	Node node5;
	node5.data=3;
	List *pList = new List();
	cout<<"从头部插入:"<<endl; 
	pList->ListInsertTail(&node1);
	pList->ListInsertTail(&node3);

	pList->ListInsertTail(&node2);
	pList->ListInsertTail(&node4);
	pList->ListInsertTail(&node5);
	pList->ListInsertTail(&node4);
    pList->ListTraverse();
    	
	pList->deleteDuplication();
	
	pList->ListTraverse();
	delete pList;
	pList = NULL;
	
	return 0;
}

           

接下来要问复杂度,我当时写的是n方,问我有没有更快的,提示我检验后一个元素与前一个元素相同就删除(这样复杂度就是n)因为给的题中数字都是连续的

以下代码输入122334,输出1234

LinkedList DeleteDuplicates_1(LinkedList L)
122 {
123     if (L == NULL || L->next == NULL||L->next->next==NULL)
124         return L;
125     //if (L == NULL || L->next == NULL)//如果不存在哨兵结点
126     //    return L;
127     Node *pre;
128     Node *p;
129     Node *pnext;
130     pre = L->next;//因为第一个结点L是哨兵结点,所以指向L的下一个结点
131     p = L->next->next;
132     //pre = L;//如果不存在哨兵结点
133     //p = L->next;
134     while (p != NULL)
135     {
136         pnext = p->next;
137         if (pre->data == p->data)
138         { 
139             pre->next = pnext;
140             free(p);
141         }
142         else
143             pre = p;
144         p = pnext;
145     }
146     return L;
147 }
           

以下代码输入122334,输出14

LinkedList DeleteDuplicates_2(LinkedList L)//如果存在哨兵结点
153 {
154     if (L == NULL || L->next == NULL || L->next->next == NULL)
155         return L;
156     Node *prere;
157     Node *pre;
158     Node *p;
159     Node *pnext;
160     int flag = 0;
161     prere = L;
162     pre = L->next;//因为第一个结点是哨兵结点
163     p = L->next->next;
164     //pre = L;//如果不存在哨兵结点
165     //p = L->next;
166     while (p != NULL)
167     {
168         pnext = p->next;
169         if (pre->data == p->data)
170         {
171             pre->next = pnext;
172             free(p);
173             flag = 1;
174         }
175         else
176         {
177             if (flag == 1)
178             {
179                 prere->next = p;
180                 free(pre);
181                 pre = p;
182                 flag = 0;
183             }
184             else
185             {
186                 prere = pre;
187                 pre = p;
188             }
189         }
190         p = pnext;
191     }
192     return L;
193 }
194 
195 LinkedList DeleteDuplicates_3(LinkedList L)//如果不存在哨兵结点
196 {
197     if (L == NULL || L->next == NULL)
198         return L;
199     Node *prere;
200     Node *pre;
201     Node *p;
202     Node *pnext;
203     int flag = 0;
204     pre = L;//如果不存在哨兵结点
205     prere = L;
206     prere--;
207     p = L->next;
208     while (p != NULL)
209     {
210         pnext = p->next;
211         if (pre->data == p->data)
212         {
213             pre->next = pnext;
214             free(p);
215             flag = 1;
216         }
217         else
218         {
219             if (flag == 1)
220             {
221                 if (pre == L)
222                 {
223                     L = p;
224                     free(pre);
225                     pre = p;
226                     prere = p;
227                     prere--;
228                 }
229                 else
230                 {
231                     prere->next = p;
232                     free(pre);
233                     pre = p;
234                 }
235                 flag = 0;
236             }
237             else
238             {
239                 prere = pre;
240                 pre = p;
241             }
242         }
243         p = pnext;
244     }
245     if (flag == 1)
246     {
247         if (pre == L)
248         {
249             L = p;
250             free(pre);
251             pre = p;
252             prere = p;
253             prere--;
254         }
255         else
256         {
257             prere->next = p;
258             free(pre);
259             pre = p;
260         }
261         flag = 0;
262     }
263     return L;
264 }
265 
266 int main()
267 {
268     LinkedList list, start;
           

整体难度不算高(但是我无了,编译出来一运行5个bug)

面试界面是这个样子,如果去别的网页的话面试官那边有提示

数据仓库高级工程师 字节跳动面试

(完)