Airbnb 面试题汇总
Posted vector11248
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Airbnb 面试题汇总相关的知识,希望对你有一定的参考价值。
Palindrome Pairs
warm up:is_palindrome
bool isPalindrome(string s)
int left = 0, right = s.size() - 1;
while (left < right)
if (s[left++] != s[right--]) return false;
return true;
给定一个字符串数组,找出所有的字符串对,该字符串对拼接起来是回文字符串(https://leetcode.com/problems/palindrome-pairs/?tab=Description)
#include <iostream>
#include <unordered_map>
#include <set>
#include <vector>
using namespace std;
bool isPalindrome(string word, int left, int right)
while (left < right)
if(word[left++] != word[right--]) return false;
return true;
vector<vector<int> > palindromePairs(vector<string>& words)
unordered_map<string, int> idx;
set<int> st;
vector<vector<int> > ans;
for (int i = 0; i < words.size(); ++i)
idx[words[i]] = i;
st.insert(words[i].length());
for (int i = 0 ; i < words.size(); ++i)
string tmp = words[i];
int len = tmp.length();
reverse(tmp.begin(), tmp.end());
if (idx.count(tmp) && idx[tmp] != i)
ans.push_back(i, idx[tmp]);
auto end = st.find(len);
for (auto it = st.begin(); it != end; ++it)
if (idx.count(tmp.substr(len - *it)) && isPalindrome(tmp, 0, len - *it - 1))
ans.push_back(i, idx[tmp.substr(len - *it)]);
if (idx.count(tmp.substr(0, *it)) && isPalindrome(tmp, *it, len - 1))
ans.push_back(idx[tmp.substr(0, *it)], i);
return ans;
int main()
vector<string> words = "bat", "tab", "cat";
auto ans = palindromePairs(words);
for (auto pr : ans)
cout << pr[0] << " "<< pr[1] <<endl;
return 0;
Round numbers
When you book on airbnb the total price is:
Total price = base price + service fee + cleaning fee + …
input : array of decimals ~ X
output : array of int ~ Y
But they need to satisfy the condition:
sum(Y) = round(sum(x))
minmize (|y1-x1| + |y2-x2| + ... + |yn-xn|)
Example1:
input = 30.3, 2.4, 3.5
output = 30 2 4
Example2:
input = 30.9, 2.4, 3.9
output = 31 2 4
先将所有floor(x)加起来统计出如果所有都floor的话还差多少,按照ceil以后需要加的价格排序,贪心取最小的补齐即可。代码如下:
# python
def roundNum(self, input):
output = map(lambda x: floor(x), input)
remain = int(round(sum(input)) - sum(output))
it = sorted(enumerate(input), key=lambda x: x[1] - floor(x[1]))
for _ in xrange(remain):
output[it.pop()[0]] += 1
return output
//c++
vector<int> roundNumber(vector<double>& prices)
vector<int> ans;
int got = 0;
double all = 0.0;
vector<pair<double, int> > s_prices;
for (int i = 0; i < prices.size(); ++i)
double price = prices[i];
int tmp = int(floor(price));
got += tmp;
ans.push_back(tmp);
all += price;
s_prices.push_back(make_pair(price, i));
sort (s_prices.begin(), s_prices.end(),
[](pair<double, int> a, pair<double, int> b)
return a.first - floor(a.first) > b.first - floor(b.first););
for (int i = 0; i < int(round(all)) - got; ++i)
ans[s_prices[i].second]++;
return ans;
2D itertaor + remove()
leetcode 251(https://leetcode.com/problems/flatten-2d-vector)
实现二维数组的迭代器,加上remove操作。代码如下:
class Vector2D
private:
vector<vector<int> >::iterator row, iBegin, iEnd;
vector<int>::iterator col;
public:
Vector2D(vector<vector<int> > &nums)
row = nums.begin();
iBegin = nums.begin();
iEnd = nums.end();
if (!nums.empty()) col = row->begin();
int next()
if (hasNext())
int val = *col;
col++;
return val;
throw "It‘s empty already!";
bool hasNext()
while (row != iEnd && col == row->end())
++row;
if(row != iEnd)
col = row->begin();
return row != iEnd;
void remove()
if (col == row->begin())
auto pre = prev(row);
while (pre != iBegin && (*pre).empty())
pre = prev(pre);
if (!(*pre).empty())
(*pre).erase(prev((*pre).end()));
else
throw "Should call next() first!";
else
(*row).erase(prev(col));
col--;
;
ip2cidr
给出一个ipv4的range,找出最少的cidr可以覆盖这个range内的所有ip。
参考:
背景介绍https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing
这个是个online转化工具http://www.ipaddressguide.com/cidr
大概的思路是group as much IPs as you can.
描述起来还真的麻烦呢,建议跑几个case,就理解了
code: http://stackoverflow.com/questions/33443914/how-to-convert-ip-address-range-to-cidr-in-java
解释: ——代表end-start能覆盖到的二进制位
start:xxxxxxx100000
end: xxxxxx——-这种情况下,先找出可以覆盖住xxxxxxx100000~xxxxxxx111111的cidr,start变为xxxxxxx100000 + 100000
end: xxxxxxxxx—-这种情况下,先找出可以覆盖住xxxxxxx100000~xxxxxxx101111的cidr,start变为xxxxxxx100000 + 10000
def ipToVal(ip):
ip = ip.split(".")
val = 0
for x in ip:
val = (val << 8) + int(x)
return val
def ValToIp(val):
ip, i = ["0"] * 4, 3
while val:
ip[i] = str(val % (1 << 8))
val /= (1 << 8)
i -= 1
return ".".join(ip)
def range2cidr(start, end):
if not start or not end or start.count(‘.‘) != 3 or end.count(‘.‘) != 3:
return None
start, end = ipToVal(start), ipToVal(end)
if start > end:
return None
ans = []
while start <= end:
firstOne = start & (-start)
maxMask = 32 - int(log(firstOne, 2))
maxDiff = 32 - int(floor(log(end - start + 1, 2)))
maxMask = max(maxMask, maxDiff)
ip = ValToIp(start)
ans.append(ip + "/" + str(maxMask))
start += 2 ** (32 - maxMask)
return ans
//C++
long ipToVal(string ip)
long val = 0;
int i = 0;
for (int j = 0; i < 4 && j < ip.length(); ++i)
auto nx = ip.find(‘.‘, j);
if (nx == ip.npos)
val = (val << 8) + atoi(ip.substr(j).c_str());
++i;
break;
val = (val << 8) + atoi(ip.substr(j, nx - j).c_str());
j = nx + 1;
if (i != 4) throw "The ip is incorrect";
return val;
string valToIp(long val)
string ip = "";
for (int i = 0; i < 4; ++i)
ip = to_string(val % 256) + "." + ip;
val /= 256;
ip.pop_back();
return ip;
vector<string> range2cidr(string start, string end)
// try...catch
long st = ipToVal(start), ed = ipToVal(end);
vector<string> ans;
while (st <= ed)
int lastOne = st & (-st);
int maxMask = 32 - int((log(lastOne)/log(2)));
int maxDiff = 32 - int(floor(log(ed - st + 1)/log(2)));
maxMask = max(maxMask, maxDiff);
string ip = valToIp(st);
ans.push_back(ip + "/" + to_string(maxMask));
st += int(pow(2, 32 - maxMask));
return ans;
Display Page list
用一个set来保存是否出现,加入以后删除原有元素,不够的话顺序补充
vector<vector<string> > paging(vector<string> items, int size)
vector<vector<string> > ans;
const int n = items.size();
for (int i = 0; i <= (n - 1) / size; ++i)
vector<string> tmp;
unordered_set<string> st;
for (auto it = items.begin(); it != items.end() && tmp.size() < size;)
if (st.count(*it))
++it;
continue;
st.insert(*it);
tmp.push_back(*it);
items.erase(it);
for (auto it = items.begin(); it != items.end() && tmp.size() < size;)
tmp.push_back(*it);
items.erase(it);
ans.push_back(tmp);
return ans;
menu order
点菜,菜价格为double,问如何正好花完手里的钱
解法:把菜单价格*100转成整数,题目转换成leetcode 40.Combination Sum II(https://leetcode.com/problems/combination-sum-ii/?tab=Description)
void helper(vector<int> &dish, vector<vector<double> > &ans, vector<double> &cur, int idx, int money)
if (money == 0)
ans.push_back(cur);
return;
if (idx == dish.size() || money < 0 || money < dish[idx])
return;
int cnt = 1;
while (cnt * dish[idx] <= money)
cur.push_back(dish[idx] / 100.0);
helper(dish, ans, cur, idx + 1, money - cnt * dish[idx]);
++cnt;
while (--cnt) cur.pop_back();
helper(dish, ans, cur, idx + 1, money);
vector<vector<double> > menuOrder(vector<double>& dish, double money)
vector<int> tmp;
vector<vector<double> > ans;
vector<double> cur;
for (auto d : dish)
tmp.push_back(int(d * 100));
sort(tmp.begin(), tmp.end());
helper(tmp, ans, cur, 0, int(money * 100));
return ans;
Hilbert Curve
Hilbert Curve(http://bit-player.org/extras/hilbert/hilbert-construction.html)
Hilbert曲线可以无限阶下去,从1阶开始,落在一个矩阵里,让你写个function,三个参数(x,y,阶数),return 这个点(x,y)是在这阶curve里从原点出发的第几步
int hilbertCurve(int x, int y, int iter)
if (iter == 0) return 1;
int areaCnt = (1 << (iter * 2 - 2)); // 每一块区域边长的边界值
int borderLen = (1 << (iter - 1)); // 区域移动的长度
if (x >= borderLen && y >= borderLen) //右上角区域 = 前一阶往右上角移动borderLen
return areaCnt * 2 + hilbertCurve(x - borderLen, y - borderLen, iter - 1);
else if (x < borderLen && y >= borderLen) //左上角区域 = 前一阶往上移动borderLen
return areaCnt + hilbertCurve(x, y - borderLen, iter - 1);
else if (x < borderLen && y < borderLen) //右下角区域 = 前一阶按照y=x对称
return hilbertCurve(y, x, iter - 1);
else //右下角区域 = 前一阶按照y=-x对称,然后右移2*borderLen - 1,上移borderLen - 1
// 设原来坐标(a,b) => (-b, -a) => (2*borderLen - 1 - b, borderLen - 1 - a) = (x, y)
// => a = borderLen - 1 - y, b = 2*borderLen - 1 - x
return areaCnt * 3 + hilbertCurve(borderLen - 1 - y, 2 * borderLen - 1 - x, iter - 1);
Alien Dictionary
leetcode 269
string alienOrder(vector<string> &words)
unordered_map<char, unordered_set<char> > mp;
unordered_map<char, int> idx;
unordered_set<char> st;
queue<char> q;
string ans = "";
for (auto word : words) st.insert(word.begin(), word.end());
for (int i = 0; i < words.size() - 1; ++i)
int j = 0, end = min(words[i].size(), words[i + 1].size());
for (; j < end; ++j)
if (words[i][j] == words[i + 1][j]) continue;
mp[words[i][j]].insert(words[i + 1][j]);
break;
if (j == end && words[i].size() > words[i + 1].size())
return ans;
for (auto m : mp)
for (auto s : m.second)
idx[s]++;
for (auto s : st)
if (!idx.count(s))
q.push(s);
ans += s;
while (!q.empty())
char c = q.front();
q.pop();
auto next = mp[c];
for (auto s : next)
if (--idx[s] == 0)
q.push(s);
ans += s;
return ans.size() == st.size() ? ans : "";
有向图 求最少的点可以遍历所有点
(https://instant.1point3acres.com/thread/201190,https://instant.1point3acres.com/thread/197716)
解法,scc(strongly connected component)缩点 + 拓扑排序,太尼玛复杂了。。
解scc用了Kosaraju算法, 拓扑排序,代码如下:
void dfs(const vector<vector<bool> > &edges, vector<bool> &visited, vector<unordered_set<int> > &components, int idx, int id)
visited[idx] = true;
if (components.size() == id) components.push_back();
components[id].insert(idx);
for (int i = 0; i < edges.size(); ++i)
if (edges[i][idx] && !visited[i]) dfs(edges, visited, components, i, id);
void preDFS(const vector<vector<bool> > &edges, vector<bool> &visited, vector<int> &orders, int idx)
visited[idx] = true;
orders.push_back(idx);
for (int i = 0; i < edges.size(); ++i)
if (edges[idx][i] && !visited[i]) preDFS(edges, visited, orders, i);
vector<int> traverse(vector<vector<bool>> &edges)
const auto n = edges.size();
vector<int> ans;
if (n == 0) return ans;
vector<bool> visited(n, false);
vector<int> orders;// 记录伪拓扑排序的顺序
vector<unordered_set<int> > components;//记录scc都包含哪些元素
int id = 0;
for (int i = 0; i < n; ++i)
if (!visited[i])
preDFS(edges, visited, orders, i);
fill(visited.begin(), visited.end(), false);
for (int i = n - 1; i >= 0; --i)
if (!visited[orders[i]])
dfs(edges, visited, components, orders[i], id);
++id;
unordered_map<int, int> in;
unordered_map<int, unordered_set<int> > next;
for (int from = 0; from < id; ++from)
for (int to = 0; to < id; ++to)
if (from == to) continue;
bool found = false;
for (auto x : components[from])
if (found) break;
for (auto y : components[to])
if (edges[x][y])
in[to]++;
next[from].insert(to);
found = true;
break;
for (int i = 0; i < id; ++i)
if (in[i] == 0)
ans.push_back(*components[i].begin());
return ans;
c++(scc + union search)
typedef pair<int, int> pr;
typedef unordered_map<int, unordered_set<int> > connectInfo;
void fromDFS(int node, connectInfo from, vector<int>& order, unordered_set<int>& visited)
if(!visited.count(node))
visited.insert(node);
for(auto n : from[node])
fromDFS(n, from, order, visited);
order.insert(order.begin(), node);
void toDFS(int node, int root, connectInfo to, unordered_map<int, int>& components)
if(!components.count(node))
components[node] = root;
for(auto n : to[node])
toDFS(n, root, to, components);
unordered_map<int, int> kosasrajus(connectInfo from, connectInfo to, const unordered_set<int>& nodes)
unordered_set<int> visited;
unordered_map<int, int> components;
vector<int> order;
for(auto node : nodes)
fromDFS(node, from, order, visited);
for(auto node : order)
toDFS(node, node, to, components);
return components;
vector<int> least_nodes(const vector<pr>& edges)
connectInfo from, to;
unordered_set<int> nodes;
vector<int> ans;
for(auto edge : edges)
from[edge.first].insert(edge.second);
to[edge.second].insert(edge.first);
nodes.insert(edge.first);
nodes.insert(edge.second);
unordered_map<int, int> components = kosasrajus(from, to, nodes);
unordered_set<int> fromComponents, toComponents;
for(auto edge : edges)
fromComponents.insert(components[edge.first]);
if(components[edge.first] != components[edge.second])
toComponents.insert(components[edge.second]);
for(auto node : fromComponents)
if(!toComponents.count(node))
ans.push_back(node);
return ans;
python:
def least_nodes(edges):
pred = collections.defaultdict(set)
succ = collections.defaultdict(set)
for start, end in edges:
pred[end].add(start)
succ[start].add(end)
components = kosarajus(pred, succ)
component_pred = collections.defaultdict(set)
component_succ = collections.defaultdict(set)
for start, end in edges:
if components[start] != components[end]:
component_start = components[start]
component_end = components[end]
component_pred[component_end].add(component_start)
component_succ[component_start].add(component_end)
return set(component_succ.keys()) - set(component_pred.keys())
def kosarajus(pred, succ):
all_nodes = set(pred.keys()) | set(succ.keys())
order = []
visited = set()
def visit(node):
if node not in visited:
visited.add(node)
for out_neighbor in succ[node]:
visit(out_neighbor)
order.insert(0, node)
for node in all_nodes:
visit(node)
components =
def assign(node, root):
if node not in components:
components[node] = root
for in_neighbor in pred[node]:
assign(in_neighbor, root)
for node in order:
assign(node, node)
return components
meeting room
给一组meetings(每个meeting由start和end时间组成)。求出在所有输入meeting时间段内没有会议,也就是空闲的时间段。每个subarray都已经sort好。N个员工,每个员工有若干个interval表示在这段时间是忙碌的。求所有员工都不忙的intervals。
循环merge,然后遍历空闲区间(ps:另一种解法很简单,参考:这题最简单的方法就是把所有区间都拆成两个点,然后排序,然后扫描,每次碰到一个点如果是左端点就把busy_employees加1,否则减1,等到每次busy_employees为0时就是一个新的区间。这样复杂度O(MlogM),M是总共区间数。)
//merge and search
vector<pr> merge(vector<pr> ft, vector<pr> sd) //c++, merge
if(ft.empty()) return sd;
if(sd.empty()) return ft;
vector<pr> ans;
const int m = ft.size(), n = sd.size();
int i = 0, j = 0;
pr tmp(1, 1);
while(i < m || j < n)
if ((i == m || tmp.second < ft[i].first) && (j == n || tmp.second < sd[j].first))
ans.push_back(tmp);
if(i == m) tmp = sd[j];
else if(j == n) tmp = ft[i];
else
tmp.first = min(ft[i].first, sd[j].first);
tmp.second = min(ft[i].second, sd[j].second);
if(i < m && ft[i].first <= tmp.second)
tmp.second = max(tmp.second, ft[i++].second);
if(j < n && sd[j].first <= tmp.second)
tmp.second = max(tmp.second, sd[j++].second);
ans.push_back(tmp);
return ans;
vector<pr> meetingRoom(vector<vector<pr> > meetings)
vector<pr> ans, tmp;
const int n = meetings.size();
if(n == 0) return ans;
tmp = meetings[0];
for(int i = 1; i < n; ++i)
tmp = merge(tmp, meetings[i]);
if(tmp[0].first > 1)
ans.push_back(make_pair(1, tmp[0].first));
for(int i = 0; i < tmp.size() - 1; ++i)
ans.push_back(make_pair(tmp[i].second, tmp[i + 1].first));
return ans;
//break and sort: C++
typedef pair<int, int> pr;
typedef pair<int, bool> timePoint;
vector<pr> meetingRoom(vector<vector<pr> > meetings)
vector<timePoint> times;
vector<pr> ans;
if ( meetings.empty()) return ans;
for (auto meeting : meetings)
for (auto interval : meeting)
times.push_back(make_pair(interval.first, true));
times.push_back(make_pair(interval.second, false));
sort(times.begin(), times.end());
int startCnt = 0, preTime = times[0].first;
for(auto time : times)
bool starting = time.second;
if (starting)
if (startCnt == 0 && time.first > preTime)
ans.push_back(make_pair(preTime, time.first));
++startCnt;
else
if (startCnt == 1) preTime = max(preTime, time.first);
--startCnt;
return ans;
//break and sort: python
def find_free_time(schedules):
moment_status = []
for person_schedule in schedules:
for interval in person_schedule:
moment_status.append((interval[0], True))
moment_status.append((interval[1], False))
moment_status.sort()
free_start = moment_status[0][0]
busy_count = 0
available_intervals = []
for moment, become_busy in moment_status:
if become_busy:
if busy_count == 0:
if moment > free_start:
available_intervals.append((free_start, moment))
busy_count += 1
else:
if busy_count == 1:
free_start = moment
busy_count -= 1
return available_intervals
preference list
每个人都有一个preference的排序,在不违反每个人的preference的情况下得到总体的preference的排序 拓扑排序解决(https://instant.1point3acres.com/thread/207601)
vector<int> preferenceList(vector<vector<int> > &preList)
unordered_map<int, unordered_set<int> > mp;
unordered_map<int, int> in;
vector<int> ans;
for(auto lt : preList)
for(int i = 1; i < lt.size(); ++i)
mp[lt[i - 1]].insert(lt[i]);
for(auto m : mp)
for(auto s : m.second)
in[s]++;
queue<int> q;
for(int i = 0; i < preList.size(); ++i)
if(!in.count(i))
q.push(i);
ans.push_back(i);
while(!q.empty())
int c = q.front();
q.pop();
auto next = mp[c];
for(auto s : next)
if(--in[s] == 0)
q.push(s);
ans.push_back(s);
return ans;
buddy list
你和你的兄弟都有一个wishlist,找出和你相似度最高的。follow up是给出一个max值,找出你的buddy的wishlist里不在你的wishlist里的最多max个城市,根据buddy和你的重合程度来排序
例如:
你的wishlist是 a,b,c,d
buddy1 的wishlist 是 a,b,e,f, 有两个和你的一样,所以是你的buddy
buddy2 的wishlist 是 a,c,d,g, 有三个和你的一样,也是你的budy
问题是输出一个size最多为max的推荐城市列表。当size为10时,buddy1和buddy2的wishlist中不在你的wishlist中的城市都可以加入推荐中,因为buddy2的重合度更高,所以先输出buddy2中的,所以推荐为 g,e,f 当size为2时,推荐是g,e 或 g,f
代码我只写了重合度排名,推荐的话可以按照相似度从高到低遍历,找出不在你的wishlist中的输出,输出过程中可以标记是否已经输出
def find(self, nums, nums2):
return sorted([(sum([num in set(nums) for num in nums2[i]]) / float(len(nums2[i])), i)
for i in xrange(len(nums2))])
flight ticket list
每一项包括departure, arrival, cost,然后给一个整数k, 表示最多允许k次中转。给定起始地点A,到达地点B, 要求输出从A到B的最小花费,最多k次中转。BFS一层一层扫。
def min_cost(flights, start, end, k):
info = collections.defaultdict(set)
for tour, cost in flights:
st, ed = tour.split("->")
info[st].add((ed, cost))
cur_level = start: 0
ans = 0x7FFFFFF
for _ in xrange(k + 1):
next_level =
for port, cur_cost in cur_level.iteritems():
for nx, cost in info[port]:
if nx == end:
ans = min(ans, cost + cur_cost)
else:
if nx not in next_level:
next_level[nx] = cost + cur_cost
else:
next_level[nx] = min(next_level[nx], cost + cur_cost)
cur_level = next_level
return ans
///C++: 太丑
typedef pair<string, int> costInfo;
int minCostFlight(const vector<string>& flights, string start, string end, int k)
unordered_map<string, set<costInfo> > costMap;
unordered_map<string, int> reached[2];
int ans = INT_MAX;
for (auto flight : flights)
auto nx = flight.find("->", 0);
auto comma = flight.find(‘,‘, nx + 2);
string st = flight.substr(0, nx);
string ed = flight.substr(nx + 2, comma - nx - 2);
int cost = atoi(flight.substr(comma + 1).c_str());
costMap[st].insert(make_pair(ed, cost));
reached[0][start] = 0;
for (int i = 0, j = 0; i <= k; ++i)
int nxIdx = (j + 1) % 2;
reached[nxIdx].clear();
for (auto st : reached[j])
for(auto ed : costMap[st.first])
if (ed.first == end)
ans = min(ans, ed.second + st.second);
else
if (!reached[nxIdx].count(ed.first))
reached[nxIdx][ed.first] = ed.second + st.second;
else
reached[nxIdx][ed.first] = min(reached[nxIdx][ed.first], ed.second + st.second);
j = nxIdx;
return ans;
URL Shortener
(https://instant.1point3acres.com/thread/196339)
看描述好像是url里的id如果有某些位置大小写换了会导致原来的url decode有问题,需要重写encode方法,回溯改某些位的大小写判断
class decodeURL
public:
int decode(string url)
string dUrl = "kljJJ324hijkS_";
if (url == dUrl) return 848662;
return -1;
int decodeFind(string url)
return helper(url, 0);
private:
int helper(string s, int idx)
if (idx == s.length())
return decode(s);
if (isalpha(s[idx]))
int uid = helper(s.substr(0, idx) + char(tolower(s[idx])) + s.substr(idx + 1), idx + 1);
int lid = helper(s.substr(0, idx) + char(toupper(s[idx])) + s.substr(idx + 1), idx + 1);
if (uid != -1 || lid != -1)
return uid != -1 ? uid : lid;
return -1;
else
return helper(s, idx + 1);
;
wizards
There are 10 wizards, 0-9, you are given a list that each entry is a list of wizards known by wizard. Define the cost between wizards and wizard as square of different of i and j. To find the min cost between 0 and 9.
说白了,就是带权重的最短距离,最优解是Dijkstra algorithm。似乎面试官说,只要普通的BFS能得到解也是可以的,Dijkstra我最近正好写过,所以也写出来了。(https://instant.1point3acres.com/thread/218032)
def min_distance(wizards, start=0, end=9):
# info = collections.defaultdict(set)
# for idx, wizard in enumerate(wizards):
# info[idx] = set(wizard)
cur_level = start: 0
ans = 0x7FFFFFFF
for _ in xrange(10):
next_level =
for idx, cur_cost in cur_level.iteritems():
if idx >= len(wizards):
continue
for nx in wizards[idx]:
cost = cur_cost + (nx - idx) ** 2
if nx == end:
ans = min(ans, cost)
else:
if nx not in next_level:
next_level[nx] = cost
else:
next_level[nx] = min(next_level[nx], cost)
cur_level = next_level
return ans
unordered_map<int, int> bfs(const unordered_map<int, int>& preLevel, unordered_map<int, unordered_set<int> >& next, int& ans, int k, int end)
unordered_map<int, int> nextLevel;
for ( auto pre : preLevel)
for (auto nx : next[pre.first])
int dis = (nx - pre.first) * (nx - pre.first) + pre.second;
if (nx == end)
ans = min(ans, dis);
else if(!nextLevel.count(nx))
nextLevel[nx] = dis;
else
nextLevel[nx] = min(nextLevel[nx], dis);
return k == 1 ? nextLevel : bfs(nextLevel, next, ans, k - 1, end);
int wizards(const vector<vector<int> > &wizards, int start, int end)
unordered_map<int, unordered_set<int> > next;
unordered_map<int, int> curLevel;
int ans = INT_MAX;
curLevel[start] = 0;
for (int i = 0; i < wizards.size(); ++i)
for (auto nx : wizards[i])
next[i].insert(nx);
bfs(curLevel, next, ans, end, end);
return ans;
模拟倒水
water land。 比如terrian是[3,2,1,2] print出来就是
*
* * *
* * * *
* * * *
然后给你一个dumpPoint,一个waterAmount,比如dumpPoint 1, waterAmount 2,因为有重力,所以是从index 2开始加水
*
* * w *
* * * *
* * * *
terrian两边是最高,模拟,先向左找到非递增的最低点,如果该点和dumpPoint一样高,往右继续找非递增的最低点,如果一样高就放到dumpPoint,不一样的话放置在非递增的最低点
void getWaterLevel(vector<int> &height, int position, int count)
if(height.empty()) return;
const int n = height.size();
vector<int> water(n, 0);
while(count--)
int putLocation = position;
int left = position, right = position;
while(left >= 1)
if(height[left - 1] + water[left - 1] > height[left] + water[left]) break;
--left;
if(height[left] + water[left] < height[position] + water[position])
putLocation = left;
else
while(right < n - 1)
if(height[right + 1] + water[right + 1] > height[right] + water[right]) break;
++right;
if(height[right] + water[right] < height[position] + water[position])
putLocation = right;
water[putLocation]++;
int highest = 0;
for(int i = 0; i < n; ++i)
if(height[i] + water[i] > highest)
highest = height[i] + water[i];
for(int h = highest; h >= 1; --h)
for(int i = 0; i < n; ++i)
if(height[i] + water[i] < h) cout<<" ";
else if(height[i] < h) cout<<"w";
else cout<<"*";
cout<<endl;
text justification
leetcode 68(https://leetcode.com/problems/text-justification/?tab=Description)
vector<string> justify(vector<string> &words, int L)
vector<string> ans;
const int n = words.size();
for (int i = 0; i < n;)
int num = 0, len = 0;
while (i + num < n && words[i + num].size() + len <= L - num)
len += words[i + num].size();
++num;
string tmp = words[i];
for (int j = 1; j < num; ++j)
if (i + num >= n) tmp += " ";
else tmp += string((L - len) / (num - 1) + (j <= (L - len) % (num - 1)), ‘ ‘);
tmp += words[i + j];
tmp += string(L - tmp.size(), ‘ ‘);
ans.push_back(tmp);
i += num;
return ans;
string pyramids transition matrix
给一个满二叉树的所有叶子,比如 A B C D E F, 然后给一个map,记录了左右孩子分别给了的时候,父亲节点可能的值。例如 左 A 右 B =》 AC,意味着倒数第二层第一个节点可以是A或者是C。然后要求是给几个字母,问这个树的root节点是否可能是这几个字母之一。follow up是加速,记忆化搜索(不是很好写)。
def generate_status(all_status, matrix):
if len(all_status) == 1:
return all_status[0]
next_all_status = []
for i in xrange(len(all_status) - 1):
cur_status = set()
for first in all_status[i]:
for second in all_status[i + 1]:
cur_status |= set(list(matrix[first][second]))
next_all_status.append(cur_status)
return generate_status(next_all_status, matrix)
def is_legal_status(nodes, status, matrix):
all_status = [set(node) for node in nodes]
return status in generate_status(all_status, matrix)
nodes = "ABCD"
matrix = collections.defaultdict(lambda: collections.defaultdict(list))
matrix[‘A‘][‘A‘] = [‘B‘]
matrix[‘A‘][‘B‘] = [‘A‘, ‘C‘]
matrix[‘A‘][‘C‘] = [‘D‘]
matrix[‘A‘][‘D‘] = [‘A‘]
matrix[‘B‘][‘A‘] = [‘D‘]
matrix[‘B‘][‘B‘] = [‘B‘, ‘C‘]
matrix[‘B‘][‘C‘] = [‘A‘]
matrix[‘C‘][‘D‘] = [‘B‘]
print is_legal_status(nodes, ‘D‘, matrix)
typedef unordered_map<char, unordered_map<char, unordered_set<char> > > matrixInfo;
void generateStatus(vector<unordered_set<char> >& allStatus, matrixInfo& matrix)
if (allStatus.size() == 1) return;
const int n = allStatus.size();
for (int i = 0; i < n - 1; ++i)
unordered_set<char> st;
for (auto first : allStatus[i])
for (auto second : allStatus[i + 1])
st.insert(matrix[first][second].begin(), matrix[first][second].end());
allStatus[i] = st;
allStatus.pop_back();
generateStatus(allStatus, matrix);
bool checkStatus(matrixInfo& matrix, char result, const string status)
vector<unordered_set<char> > allStatus;
for (auto c : status)
unordered_set<char> tmp;
tmp.insert(c);
allStatus.push_back(tmp);
generateStatus(allStatus, matrix);
return allStatus[0].count(result) != 0;
int main()
matrixInfo mi;
mi[‘A‘][‘A‘].insert(‘B‘);
mi[‘A‘][‘B‘].insert(‘A‘);
mi[‘A‘][‘B‘].insert(‘C‘);
mi[‘A‘][‘C‘].insert(‘D‘);
mi[‘A‘][‘D‘].insert(‘A‘);
mi[‘B‘][‘A‘].insert(‘D‘);
mi[‘B‘][‘B‘].insert(‘B‘);
mi[‘B‘][‘B‘].insert(‘C‘);
mi[‘B‘][‘C‘].insert(‘A‘);
mi[‘C‘][‘D‘].insert(‘B‘);
cout<<checkStatus(mi, ‘A‘, "ABCD")<<endl;
sliding game
九宫格,一共8个方块,从1-8,一个方块空出来,然后打乱之后通过SLIDE还原,这个题要推广到N宫格,先实现这个游戏,然后对于一个任意的BOARD,要你把他解出来
def dis(x, y): # A* evaluation func
return (x - 2) ** 2 + (y - 2) ** 2
def play(board):
m, n = len(board), len(board[0])
x, y = 0, 0
for i in xrange(m):
for j in xrange(n):
if board[i][j] == ‘0‘:
x, y = i, j
board_key = ‘‘.join(‘‘.join(row) for row in board)
heap = [(dis(x, y), x, y, board_key)]
visited = set()
while heap:
_, x, y, cur = heapq.heappop(heap)
if cur in visited:
continue
visited.add(cur)
if cur == "123456780":
return True
for dx, dy in zip((1, -1, 0, 0), (0, 0, 1, -1)):
new_x, new_y = x + dx, y + dy
if 0 <= new_x < m and 0 <= new_y < n:
pos1, pos2 = x * m + y, new_x * m + new_y
new_board = list(cur)
new_board[pos1], new_board[pos2] = new_board[pos2], new_board[pos1]
heapq.heappush(heap, (dis(new_x, new_y), new_x, new_y, ‘‘.join(new_board)))
return False
typedef tuple<int, int, int, string> boardInfo;
bool validSlidingGame(vector<vector<int> >& board)
const int m = board.size(), n = board[0].size();
auto dis = [](int x, int y, int z, int p) return (x - z) * (x - z) + (y - p) * (y - p); ;
int x = 0, y = 0;
string key = "";
const int dir[4][2] = 1, 0, -1, 0, 0, 1, 0, -1;
priority_queue<boardInfo> pq;
unordered_set<string> visited;
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
if (board[i][j] == 0)
x = i, y = j;
key += to_string(board[i][j]);
pq.push(make_tuple(-dis(x, y, m - 1, n - 1), x, y, key));
visited.insert(key);
while (!pq.empty())
auto tp = pq.top();
pq.pop();
string curKey;
tie(ignore, x, y, curKey) = tp;
// x = get<1>(tp), y = get<2>(tp);
// auto curKey = get<3>(tp);
if (curKey == "123456780") return true;
for (int i = 0; i < 4; ++i)
int newX = x + dir[i][0];
int newY = y + dir[i][1];
if (newX >= 0 && newX < m && newY >= 0 && newY < n)
swap(curKey[x * m + y], curKey[newX * m + newY]);
if (!visited.count(curKey))
pq.push(make_tuple(-dis(newX, newY, m - 1, n - 1), newX, newY, curKey));
visited.insert(curKey);
return false;
find median from large file of integers
https://instant.1point3acres.com/thread/159344
二分查找
思路就是:先找在INT_MIN和INT_MAX的median(0?),然后读large file of integers,找出比这个数小的个数是否有一半,然后调整二分的边界
double findNth(int N, int left, int right)
while(left <= right)
int guess = (left + right) / 2;
int x, cnt = 0, next = right;
while(x = readFile())
if(x < guess) ++cnt;
else next = min(next, x);
if(cnt == N - 1)
return next;
if(cnt < N - 1)
left = guess;
else
right = guess - 1;
return 0.0;
double findMedian()
int len = 0;
while(readFile()) ++len;
if(len & 0x1) return findNth(len >> 1, INT_MIN, INT_MAX);
int x = findNth(len >> 1, INT_MIN, INT_MAX);
int y = findNth(1 + (len >> 1), x, INT_MAX);
return double(x + y) / 2;
Multiply Strings
但是string里面的数可以为负
leetcode 43题,多了个负数的情况(https://leetcode.com/problems/multiply-strings/?tab=Description)
#include <iterator>
#include <algorithm>
#include <vector>
typedef vector<int> bigInt;
bigInt make_bigInt(string num)
bigInt tmp;
transform(num.rbegin(), num.rend(), back_inserter(tmp), [](char c) return c - ‘0‘;);
return tmp;
string make_string(bigInt num)
string tmp;
transform(find_if(num.rbegin(), prev(num.rend()), [](int c) return c != 0;), num.rend(),
back_inserter(tmp), [](int c) return c + ‘0‘;);
return tmp;
bigInt multiply(bigInt const& n1, bigInt const& n2)
bigInt n(n1.size() + n2.size());
for (int i = 0; i < n1.size(); ++i)
for (int j = 0; j < n2.size(); ++j)
n[i + j] += n1[i] * n2[j];
n[i + j + 1] += n[i + j] / 10;
n[i + j] %= 10;
return n;
string multiply(string num1, string num2)
if(num1.empty() || num2.empty()) return "0";
bool sign = true;
if (num1[0] == ‘-‘ || num1[0] == ‘+‘)
if (num1[0] == ‘-‘) sign = !sign;
num1.sustr(1);
if (num2[0] == ‘-‘ || num2[0] == ‘+‘)
if (num2[0] == ‘-‘) sign = !sign;
num2.sustr(1);
string ans = make_string(multiply(make_bigInt(num1), make_bigInt(num2)));
if (ans == "0") return ans;
return (sign ? "" : "-") + ans;
CSV PARSER
举个例子:
给定一个CSV文件,格式是 “some_name|some_address|some_phone|some_job”
要求输出Json format “name:some_name, address:some_addres,phone:some_phone, job:some_job”
输入内容中有些特殊符号要注意处理
vector<string> parseCSV(string s)
vector<string> ans;
bool inQuote = false;
string tmp = "";
for(int i = 0; i < s.length(); ++i)
if(inQuote)
if(s[i] == ‘"‘)
if(i == s.length() - 1)
ans.push_back(tmp);
return ans;
else if(s[i + 1] == ‘"‘)
tmp += ‘"‘;
++i;
else
ans.push_back(tmp);
tmp = "";
inQuote = false;
i++;
else tmp += s[i];
else
if(s[i] == ‘"‘)
inQuote = true;
else if(s[i] == ‘,‘)
ans.push_back(tmp);
tmp = "";
else tmp += s[i];
if(!tmp.empty()) ans.push_back(tmp);
return ans;
int main()
string ss[] = "John,Smith,john.smith@gmail.com,Los Angeles,1", "\"Alexandra \"\"Alex\"\"\",Menendez,alex.menendez@gmail.com,Miami,1";
for(auto s : ss)
auto parsed = parseCSV(s);
for (int i = 0; i < parsed.size() - 1; ++i)
cout << parsed[i] << "|";
cout<<parsed[parsed.size() - 1]<<endl;
return 0;
boggle game
(https://instant.1point3acres.com/thread/201695)
这题面试来搞也太变态了,先用trie找出所有单词出现的路径map,然后dfs找出map里不重复的最大的。代码未验证~
struct Node
bool isWord = false;
string word;
Node *next[26];
Node()
;
struct Trie
Node *root;
Trie()
root = new Node();
void buildTrie(const vector<string>& &words)
for(auto word : words)
Node *cur = root;
for(auto c : word)
int idx = c - ‘a‘;
if(!cur->next[idx])
cur->next[idx] = new Node();
cur = cur->next[idx];
cur->isWord = true;
cur->word = word;
;
const int dir[4][2] = 1, 0, -1, 0, 0, 1, 0, -1;
void searchBoard(const vector<vector<char> >& board, vector<vector<bool> >& visited, int x, int y, Node* root,
vector<pr>& path, unordered_map<string, vector<vector<pr>> >& mp)
if(x < 0 || x > board.size() || y < 0 || y > board[0].size() || visited[x][y])
return;
int idx = board[x][y] - ‘a‘;
if(!root->next[idx]) return;
root = root->next[idx];
path.push_back(make_pair(x, y));
visited[x][y] = true;
if(root->isWord) mp[root->word].push_back(path);
for(int i = 0;i < 4; ++i)
searchBoard(board, visited, x + dir[i][0], y + dir[i][1], root, path, mp);
visited[x][y] = false;
path.pop_back();
void dfs(int& ans, int cur, const vector<string>& words, vector<vector<bool> >& visited,
unordered_map<string, vector<vector<pr>> >& mp, int idx)
if(idx == words.size())
ans = max(ans, cur);
return;
if(ans >= cur + words.size() - idx) return;
string word = words[idx];
if(mp.count(word))
for (auto pts : mp[word])
int cnt = 0;
for (auto pt : pts)
if (visited[pt.first][pt.second]) break;
cnt++;
if (cnt == word.size())
for (auto pt : pts) visited[pt.first][pt.second] = true;
dfs(ans, cur + 1, words, visited, mp, idx + 1);
for (auto pt : pts) visited[pt.first][pt.second] = false;
dfs(ans, cur, words, visited, mp, idx + 1);
int findWords(const vector<vector<char> >& board, const vector<string>& words)
if(board.empty() || words.empty()) return 0;
Trie trie;
trie.buildTrie(words);
const auto m = board.size(), n = board[0].size();
unordered_map<string, vector<vector<pr>> > mp;
for(int i = 0; i < m; ++i)
for(int j = 0; j < n; ++j)
vector<vector<bool> > visited(m, vector<bool>(n, false));
vector<pr> path;
searchBoard(board, visited, i, j, trie.root, path, mp);
vector<vector<bool> > visited(m, vector<bool>(n, false));
int ans = 0;
dfs(ans, 0, words, visited, mp, 0);
return ans;
以上是关于Airbnb 面试题汇总的主要内容,如果未能解决你的问题,请参考以下文章