題目:
git是一種分佈式代碼管理工具,git通過樹的形式記錄文件的更改歷史,比如: base'<–base<–A<–A’ ^ | — B<–B’ 小米工程師常常需要尋找兩個分支最近的分割點,即base.假設git 樹是多叉樹,請實現一個算法,計算git樹上任意兩點的最近分割點。 (假設git樹節點數爲n,用鄰接矩陣的形式表示git樹:字符串數組matrix包含n個字符串,每個字符串由字符’0’或’1’組成,長度爲n。matrix[i][j]==’1’當且僅當git樹種第i個和第j個節點有連接。節點0爲git樹的根節點。)
輸入例子:
[01011,10100,01000,10000,10000],1,2
輸出例子:
1
分析:
- 分別倒序尋找兩個節點與根結點(0節點)的連通路。
- 將兩條通路進行匹配,尋找最近的分割點(兩條通路中第一個相同的點)。
算法代碼:
int findClosestSeperatingPoint(char **GitTree, int n, int pointA, int pointB)
{
int closestSeperatingPoint = 0;
int Ai, Aj, Bi, Bj;
Ai = Aj = pointA;
Bi = Bj = pointB;
int *pathA = new int[n];
int *pathB = new int[n];
int pathLenOfA, pathLenOfB;
//find the path of A
findPath(GitTree, pathA, pathLenOfA, pointA);
//find the path of B
findPath(GitTree, pathB, pathLenOfB, pointB);
//find the closest seperating point
closestSeperatingPoint = match(pathA, pathB, pathLenOfA, pathLenOfB);
delete [] pathA;
delete [] pathB;
return closestSeperatingPoint;
}
void findPath(char **GitTree, int *path, int & pathLen, int point)
{
int i, j;
i = j = point;
pathLen = 1;
path[pathLen-1] = point;
while (0 != i) {
while ('1' != GitTree[i][j]) {
j--;
}
pathLen++;
path[pathLen-1] = j;
i = j;
}
}
int match(int pathA[], int pathB[], int pathLenOfA, int pathLenOfB)
{
for (int i = 0; i < pathLenOfA; ++i) {
for (int j = 0; j < pathLenOfB; ++j) {
if (pathA[i] == pathB[j]) {
return pathA[i];
}
}
}
return 0;
}
中間將尋找與根結點的通路代碼和匹配兩條通路的最近分割點代碼封裝起來了。
測試代碼:
//
// main.cpp
// findClosestSeperatingPoint
//
// Created by Jiajie Zhuo on 2017/4/2.
// Copyright © 2017年 Jiajie Zhuo. All rights reserved.
//
#include <iostream>
using namespace std;
int findClosestSeperatingPoint(char **GitTree, int n, int pointA, int pointB);
void findPath(char **GitTree, int *path, int & pathLen, int point);
int match(int pathA[], int pathB[], int pathLenOfA, int pathLenOfB);
int main(int argc, const char * argv[]) {
int n, pointA, pointB, closestSeperatingPoint;
cout << "Please enter the nubmer of point: ";
cin >> n;
char **GitTree = new char*[n];
cout << "Please enter the matrix of GitTree:" << endl;
for (int i = 0; i < n; i++) {
GitTree[i] = new char[n];
for (int j = 0; j < n; j++) {
cin >> GitTree[i][j];
}
}
cout << "Please enter the two point A and B: ";
cin >> pointA >> pointB;
closestSeperatingPoint = findClosestSeperatingPoint(GitTree, n, pointA, pointB);
cout << "The closestSeperatingPoint is " << closestSeperatingPoint << endl;
for (int i = 0; i < n; ++i) {
delete [] GitTree[i];
}
delete [] GitTree;
return 0;
}
注:這裏已知git樹的節點數。
改進:
其中的path可以使用vector,添加元素和匹配時都會方便很多。
因爲path中的元素都是倒序排列的,所以最後的match()匹配方法增加效率。