Given a git commit (wiki:...), each commit has an id. Find all the commits
that we have.
给出一个Git的commit,找出所有的parents。每个节点都有一个或多个parent。
另外每个commit都是带着ID的。就是没太懂它是输出所有的commit还是要求逐层打印。
第二题就是找到两个commit的公共祖先。
Git的commit是可以分叉的也可以合并,所以这题其实是个图。
想来真是好久没弄github了。
其实就是BFS和双向BFS,注意好对复杂度的分析吧。优化就是双向BFS吧。
好像不太对。

注意解释下BFS的复杂度为什么是O(V+E)

git commit的题,也是面经题。第一问给一个commit(node),BFS输出所有commits (nodes)。第二问,两个commits (nodes),找到他们的最近的公共parent,就是先BFS一个,然后用map记录下其各个parent到这个commit(node)的距离,然后BFS第二个commit(node),碰到在map里的node,就算一个总距离,然后更新最短距离和的点,最后最短距离和的点就是结果了,写完面试官也表示很满意。这个注意解释下BFS的复杂度为什么是O(V+E),他会问为什么不是O(V)之类的。

#include <iostream>
#include <queue>
#include <vector>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>

using namespace std;
struct GitNode {
    int id;
    vector<GitNode*> parents;    
    GitNode(int x) : id(x){}
};
vector<int> findParents(GitNode* root) {
    vector<int> res;
    if (!root) return res;    //don't forget!!!!!!!!!!!
    unordered_set<int> visited;
    queue<GitNode*> toVisit;
    toVisit.push(root);
    visited.insert(root->id);    //一定要在这里insert进visited,而不是在pop的时候,因为有可能同一层的点指向同一个点
    while (!toVisit.empty()) {
        GitNode* curr = toVisit.front();
        toVisit.pop();
        res.push_back(curr->id);
        for (auto p : curr->parents)
            if (!visited.count(p->id)){
                visited.insert(p->id);
                toVisit.push(p);
            }
    }
    return res;
}
GitNode* findLCAhelper(queue<GitNode*>& toVisited, unordered_set<GitNode*>& visited, unordered_set<GitNode*>& toCheck) {
    for (int i = toVisited.size(); i > 0; i--) {
        GitNode* curr = toVisited.front();
        toVisited.pop();
        if (toCheck.count(curr)) return curr;
        for (GitNode* p : curr->parents)
            if (!visited.count(p)) {
                visited.insert(p);
                toVisited.push(p);
            }
    }
    return nullptr;
}
GitNode* findLCA(GitNode* n1, GitNode* n2) {
    if (!n1 || !n2) return nullptr;
    queue<GitNode*> toVisited1, toVisited2;
    unordered_set<GitNode*> visited1, visited2;
    toVisited1.push(n1); toVisited2.push(n2);
    visited1.insert(n1); visited2.insert(n2);
    while (!toVisited1.empty() || !toVisited2.empty()) {
        GitNode* tmp = findLCAhelper(toVisited1, visited1, visited2);
        if (tmp) return tmp;
        tmp = findLCAhelper(toVisited2, visited2, visited1);
        if (tmp) return tmp;
    }
    return nullptr;
}
int main(int argc, char *argv[]) {
    /*
    *
    *   5 <-  4  <- 2 <- 6
    *    \      \
    *     \ <- 3 <- 1
    * */
    GitNode* g1 = new GitNode(1);
    GitNode* g2 = new GitNode(2);
    GitNode* g3 = new GitNode(3);
    GitNode* g4 = new GitNode(4);
    GitNode* g5 = new GitNode(5);
    GitNode* g6 = new GitNode(6);

    g1->parents.push_back(g3);
    g1->parents.push_back(g4);
    g2->parents.push_back(g4);
    g3->parents.push_back(g5);
    g4->parents.push_back(g5);
    g6->parents.push_back(g2);

    vector<int> parents = findParents(g1);

    for (int p : parents) cout<<p<<' ';cout<<endl;    //其实这里会漏掉2。。假装是最新git的咯

    cout<<"g1,g6 "<<findLCA(g1, g6)->id<<endl;
    cout<<"g2,g3 "<<findLCA(g2, g3)->id<<endl;
    cout<<"g1,g4 "<<findLCA(g1, g4)->id<<endl;    //觉得这个test是极好的w

}

/*
6 ---------1
|         /
11 5-4-3-2
 \  \
  10-9-8-7

getLCA(1,7)
*/

results matching ""

    No results matching ""