zoukankan      html  css  js  c++  java
  • 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;
    }
    

    点菜,菜价格为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;
    }
  • 相关阅读:
    ANSI C
    如何判断机器的endianness
    union的常见用法
    主流浏览器引擎
    用宏来求数组元素个数
    inode
    分区时"磁盘上没有足够的空间完成此操作"的解决方法
    删除OEM分区
    jquery加table布局 模仿实现FaceBook Dialog
    Container.DataItem使用
  • 原文地址:https://www.cnblogs.com/vector11248/p/11473793.html
Copyright © 2011-2022 走看看