2022亚马逊校园招聘软件开发实习提前批面试题
笔试是两道题,不是很难,给了70分钟,大概30分钟做完。每个测试样例都能看做,暴力过的,不知道会不会只是pretest
面试是两面连着的,面试官说标准流程是前50分钟做两道题,后10分钟其他。如果面试官对你简历上的内容很感兴趣,可能会打破常规。
说下面试题吧
一面
一面面试官是男的,说对我的简历内容很感兴趣,所以先问了一下项目
第一题
题目:给定一些网页的跳转关系,例如A->B->F->D...,求从网页X跳到网页Y的最小次数
方法:就相当于求图中的最短路,由于是无权重的,用BFS即可。
不要求运行,所以心理没啥压力,但是面试官是会一行一行review的
第二题
由于我简历上有个epoll多路复用+线程池的项目,面试官要求我简易实习一个工作队列
这个题目非常有意思,毕竟自己的项目,多少还有点印象
- 初代
struct Job {
int id;
func run_func;
}
struct ThreadPool {
thread threads[8]; // 8个线程
mutex m; // 互斥锁
cond_variable cond; // 条件变量
queueq; // 任务队列
ThreadPool() {
for(int i = 0;i < 8;i++) {
pthread_create(&threads[i], work_func);
}
}
void schedule(std::function func);
void work_func() {
get_mutex(m);
pthread_cond_wait(cond);
job = q.front(); // 取出就绪的任务执行
q.pop();
job->run_func();
release_mutex(m);
}
void add(Job job) {
get_mutex(m);
q.push(job); // 添加一个job到任务队列中
pthread_cond_post(cond);
release_mutex(m);
}
}
-
二代
我啪啦啪啦写完了,面试官说互斥锁和条件变量不需要初始化吗?遂加上 -
三代
面试官说,如果一个job执行了很久,由于work_func没有释放锁,其他线程并没有执行,这样多线程变成了单线程
啊这,确实如此
可以稍加改动,将执行函数提出来
void work_func() {
get_mutex(m);
pthread_cond_wait(cond);
job = q.front(); // 取出就绪的任务执行
q.pop();
// job->run_func();
release_mutex(m);
job->run_func();
}
- 最终
面试官逐行review,提出一个死锁情况:当任务队列为空时,work_func拿到了锁,但是由于没有就绪任务,会停在pthread_cond_wait,而新的任务又不能加入队列,因为add没法获得锁
我当时忘记pthread_cond_wait的用法了(后面会讲,其实这么写不会死锁),想了想,确实存在这种情况,只能再改了
我将mutex的作用域改到最小,即只用于队列的互斥
void work_func() {
pthread_cond_wait(cond);
get_mutex(m);
// pthread_cond_wait(cond);
job = q.front(); // 取出就绪的任务执行
q.pop();
release_mutex(m);
job->run_func();
}
void add(Job job) {
get_mutex(m);
q.push(job); // 添加一个job到任务队列中
// pthread_cond_post(cond); // 这个可以不改,当为了统一,也放到外面
release_mutex(m);
pthread_cond_post(cond);
}
其实并不会死锁,我查看了之前项目的写法,写的pthread_cond_post(cond, m)
,其含义是:
pthread_cond_wait会先解除之前的pthread_mutex_lock锁定的m,然后阻塞在等待对列里休眠,直到再次被唤醒(大多数情况下是等待的条件成立而被唤醒,唤醒后,该进程会先锁定先pthread_mutex_lock(&m);再读取资源。
所以并不会死锁,但是修改后的也不会死锁啦
二面
二面是个xjj,也没说其他的,直接做题
第一题 Leetcode 49. 字母异位词分组
发现是Leetcode原题。。。我是用hash统计单词,再用hash统计hash。
xjj一直问我对单词的hash可以优化吗,char[26];
char[26]再用hash统计需要重写hash函数吧??我说可以做进制编码变成整数,她提示可以用string
贴一个面试时写的巨丑的代码:
点击查看代码
Given an array of strings strs, group the anagrams together. You can return the answer in any order.
An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.
Input: strs = ["eat","tea","tan","ate","nat","bat"]
Output: [["bat"],["nat","tan"],["ate","eat","tea"]]
N, l = l*n^2
bool check(string s1, string s2) {
unordered_mapmp, mp2;
for(char ch : s1) mp[ch]++;
for(char ch : s2) mp2[ch]++;
for(char ch : s1) {
if(mp[ch] != mp2[ch]) return false;
}
return true;
}
vector> strGroup(vector strs) {
int n = strs.size();
unordered_map>mp; // a group
for(int i = 0;i < n;i++) {
for(int j = 0;j < i;j++) {
if(strs[j] == strs[i]) {
mp[strs[i]].push_back(strs[j]); // some group put together
}
}
}
vector>res;
for(auto it = mp.begin(); it != mp.end();it++) {
res.push(it->second);
}
return res;
}
bool cmp(string s1, string s2) {
unordered_mapmp, mp2;
for(char ch : s1) mp[ch]++;
for(char ch : s2) mp2[ch]++;
for(char ch : s1) {
if(mp[ch] != mp2[ch]) return false;
}
return true;
}
vector> strGroup(vector strs) {
unordered_map mp;
vector, string>, cmp>hashtables;
for(string str : strs) { // o(N)
mp.clear();
for(int i = 0;i < str.size();i++) { o(l)
mp[str[i]]++;
}
hashtables.push_back(make_pair(mp, str));
}
unordered_map, vector>groups;
for(auto hashtable : hashtables) { // o(N)
groups[hashtable.first].push_back(hashtables.second);
}
// convert
vector>ans;
for(auto group : groups) {
ans.push_back(group);
}
return ans;
}
几行代码能写完的东西,我写出这样的丑八怪,离谱!!
贴个养眼的:
class Solution {
public:
vector> groupAnagrams(vector& strs) {
unordered_map>mp;
int freq[26];
for(string& str : strs) {
memset(freq, 0, sizeof freq);
for(char& ch : str) freq[ch-'a']++;
string s = "";
for(int i = 0;i < 26;i++) s += freq[i]+'0';
mp[s].push_back(str);
}
vector>ans;
for(auto it = mp.begin(); it != mp.end();it++)
ans.push_back(it->second);
return ans;
}
};
第二题
题目:
Q2.
Minimize the distance to the farthest point
Assume you're looking to move, and have a set of amenities that you want to have easy access to from your new home.
You have found a neighborhood you like, each block of which has zero or more amenities.
How would you pick the block to live in such that the farthest distance to any amenity in your list is minimized?
Example:
Blocks = [
{restaurant, grocery}, // 2, 0 => 2
{theater}, // 1, 1 => 1
{school}, // 0, 2 => 2
{},
{school},
]
Requirements = {restaurant}
Requirements = {school, grocery}
大概就是,有n个街区,每个街区有一些地点,现给定一些地点,要你选择一个街区,它到给定的那些地点的最大距离最小
方法:维护每个街区到每个地点的最小距离,从前往后和从后往前 都遍历一遍,然后枚举每个街区,就能得到最终的最小值
我维护了所有的地点,面试官一直说可以不用维护这么多,原来她指的是可以只维护题目问的,我最后才弄明白她的意思...
block1: hash[school] = INF, hash[grocery] = 0, hash[restaurant] = 0, hash[theater] = INF
block2: hash[school] = INF, hash[grocery] = +1, hash[restaurant] = +1, hash[theater] = 0
vector get_all_place(vector> blocks) {
}
void minDistance(vector> blocks, vectorrequirements) {
vector< unordered_map> distances; // for each block
vector all_place = get_all_place(blocks);
int i = 0;
for(auto block : blocks) {
block_hash = distances[i];
for(string palce : all_place) {
if(palce in block) {
block_hash[palce] = 0;
} else {
bloack_hash[place] += 1;
}
}
i++;
}
i = n-1;
for(auto block : reverse(block)) {
block_hash = distances[i];
for(string palce : all_place) {
int tmp;
if(palce in block) {
tmp = 0;
} else {
tmp += 1;
}
block_hash[palce] = min( block_hash[palce], tmp); //
}
i--;
}
int ans = INF;
int pos;
for(string requirement : requirements) {
for(int i = 0;i < blocks.size();i++) {
hash_table = distances[i];
int tmp_min = -INF;
for(auto it = hash_table.begin(); it != hash_table.end();it++) {
if(it->second > tmp_min) {
tmp_min = it->second;
}
}
if(tmp_min < ans) {
ans = tmp_min;
pos = i;
}
}
}
return pos;
}
感想
不问八股文真的好爽,没有那些乱七八糟的问题让人自我怀疑
常数级的时间/空间优化也是必要的,在面试的时候,因为面试官通常也能看出来,不优化的话,我个人觉得印象分会降低