【就像回字有四种写法,LCA也有六种求法】(最近公共祖先求解)

 都加了注释,可以当算法模板使用,注意思考每种方法的适用场景

目录

方法一

方法二

 方法三

方法四

方法五

方法六


方法一

struct Binary{
struct Node{
	struct Node *left  {nullptr};
	struct Node *right {nullptr};
	int                      tag;
    // different node has differed tag
	inline bool operator==(const Node& other) const
	{ return tag == other.tag; }
} *root {}; // a tree node definition
// a binary tree must have a root( may be nil root)

//f __lca__ called by f lca, update the answer node pointer
bool __lca__(Node **ans, Node *o, Node *p, Node *q) const{
	if(!o) return false;
	bool left_flag { __lca__(ans, o->left, p, q) };
	bool right_flag { __lca__(ans, o->right, p, q) };
	bool condition_one { (*o == *p || *o == *q) && (left_flag || right_flag) };
	bool condition_two { left_flag && right_flag };
	if( condition_one || condition_two )
	// lca of node p and node q must satisfy this condition
    // either meet the condition that :
    //     both left-subtree and right-subtree maintain one of node p or q
    // or meet the condition that:
    //     x is node p or q itself and one of its subtree holds another node to be found
		*ans = o;
	return condition_one;
}
Node *lca(Node *p, Node *q) const{
	if(!root || !p || !q) return nullptr;
    //special judge

	Node *ans {};
	__lca__(&ans, root, p, q);
	//pass a double pointer
	return ans;
}
};

方法二

 

struct Binary{
struct Node{
	struct Node *left  {nullptr};
	struct Node *right {nullptr};
	int                      tag;
    // tag is to distinguish two differed node
	inline bool operator==(const Node& other) const
	{ return tag == other.tag; }
    //operator== override
} *root {}; // init with a nil root
//tree node definition

std::unordered_map<int, Node *> parent;
//hashmap to record every node's parent
//specially, root's parent is null

void dfs(Node *o){
	if(!o) return;
	if(o->left) parent[o->left->tag] = o;
	if(o->right) parent[o->right->tag] = o;
	dfs(o->left);
	dfs(o->right);
}
//iterate the whole tree to find nodes' parent

Node *lca(Node *p, Node *q) const{
    //special judge
	if(!root || !p || !q) return nullptr;

	dfs(root);
    //update the parent

	std::unordered_map<int, bool  > visited;
	while(p){
		visited[p->tag] = true;
		p = parent[p->tag];
	}
    //record the path from p directly to the root

	while(q){
    //q climbing the root upward until firstly meet the path
    //    that node q has vistied before
		if(visited[q->tag]) return q;
		q = parent[q->tag];
	}
}
};

 方法三

struct Binary{
struct Node{
	struct Node *left  {nullptr};
	struct Node *right {nullptr};
	int                      tag;
    //data tag is to represent differed nodes
	inline bool operator==(const Node& other) const
	{ return tag == other.tag; }
    //operator== override by nodes' tag
} *root {}; // bin-tree initialized with a nil root
//treenode definition

std::unordered_map<int, Node *> parent;
//hashmap to record every nodes' parent
//specially, root has a nil parent

void dfs(Node *o){
	if(!o) return;
	if(o->left) parent[o->left->tag] = o;
	if(o->right) parent[o->right->tag] = o;
//dfs to update the parents
	dfs(o->left);
	dfs(o->right);
}
Node *lca(Node *p, Node *q) const{
	if(!root || !p || !q) return nullptr;
	dfs(root);
	Node *pp { p };
	Node *qq { q };
    //circularilly loop between root and p|q
    //    until pp and qq meet
	while(*pp == *qq){
		pp = pp ? parent[pp->tag] : p;
		qq = qq ? parent[qq->tag] : qq;
	}
	return pp;
}
};

方法四

struct Binary{
struct Node{
	struct Node *left  {nullptr};
	struct Node *right {nullptr};
	inline bool operator==(const Node& other) const
	{ return tag == other.tag; }
} *root {};
//tree-node definition

std::unordered_map<Node *, Node *> par;
//record the disjoined-set-uinion's parent

std::unordered_map<std::pair<Node *, Node *>, Node *> lca;
//record every quiry's lca result

std::unordered_map<Node *, bool> visited;
//record whether or not a node has been visited

std::vector<Node *> collection;
//push all nodes into a flatted array, then conviniently iterated
void dfs(Node *o){
	if(!o) return;
	collection.push_back(o);
	dfs(o->left);
	dfs(o->right);
}
//push nodes into vector


inline Node *find_par(Node *o){
	return par[o] == o ? o : (par[o] = find_par(par[o]));
}
//DSU quiry

void tarjan(Node *o){
	if(o->left){
		par[o->left] = o;
		visited[o->left] = true;
        //mark the visited flag
        // and record nodes' parent
	}
	if(o->right){
		par[o->right] = o;
		visited[o->right] = true;
	}
	auto __size__{ collection.size() };
	for(auto i {0U}; i < __size__; ++i)
		for(auto j {i + 1U}; j < __size__; ++j){
			Node *lhs { collection[i] };
			Node *rhs { collection[j] };
			Node *p   { find_par(o) };
			lca[{lhs, rhs}] = lca[{rhs, lhs}] = p;
		}
}
//tarjan: take advantage of dfs's time stamp property to handle this algorithm

Node *lca(Node *p, Node *q) const{
	if(!root || !p || !q) return nullptr;
    //special judge
    
	dfs(root);
    //dfs to collect nodes into vector

	for(auto o : collection) par[o] = o;
    //init DSU set
    
	tarjan(root);
	return lca[{p, q}];
}
};

方法五

constexpr std::size_t __MAX_NODES_{ 50001U };
constexpr std::size_t __MAX_EDGES_{ 50000U };
constexpr std::size_t __MAX_DEPTH_{ 1 << 4 | 1 };

typedef struct {
	int32_t __forward__; //forward adjacent node
	int32_t __next__; //next edge
} edge;

typedef struct {
	uint32_t __depth__;
	int32_t __ancestor__[__MAX_NODES_];
} node;

int32_t head[__MAX_NODES_];
edge edges[__MAX_EDGES_];
node nodes[__MAX_NODES_];
uint32_t tot {};
void insert(uint32_t u, uint32_t v){
//__COMMENT__: insert a edge from u to v
	edges[tot] = edge{ __forward__ : v, __next__ : head[u] };
	head[u] = tot ++;
}

inline void __init__(void){
//__COMMENT__: init the head of all edges
	std::memset(head, -1, sizeof head);
}
void getDeep(int32_t u,int32_t fa){
//__COMMENT__: dfs to update every node's depth in the tree
//                    and their levelled-ancestor
	if(fa) nodes[u].__depth__ = nodes[fa].__depth__ + 1;
	nodes[u].__ancestor__[0] = fa;
	for(auto i { 1U }; (1U<<i) < deep[cur]; ++i)
		nodes[u].__ancestor__[i] = nodes[nodes[u].__ancestor__[i-1]].__ancestor__[i-1];
		//2^i=2^(i-1)+2^(i-1) RMQ DP
	for(auto i {head[u]}; ~i; i = edges[i].__next__)
		if(!(edges[i].__forward == fa))
			getDeep(edge[i].__forward, u);
}
int32_t __lca__(int32_t u, int32_t v){
	if(nodes[u].__depth__ <  nodes[v].__depth__) return __lca__;
    //ensure the depth[u] is deeper

	for(auto h { ( int )std::ceil(std::log2(nodes[u].__depth__ - nodes[v].__depth)) + 1}; h >= 0; --h)
    //u should be to the same depth as v
		if(nodes[u].__depth <= nodes[v].__depth__)
			u = nodes[u].__ancestor__[h];
	if(u == v)return u;
    //early return

	for(auto i {( int )std::ceil(std::log2(nodes[u].__depth__) + 1}; i>=0; --i)
		if(!(nodes[u].__ancestor__[i] == nodes[v].__ancestor__[v])){
			u = nodes[u].__ancestor__[i];
			v = nodes[v].__ancestor__[i];
		}
    //u and v climb together with the same depth-step
    // and should be meet under the their lca in the tree
	return nodes[u].__ancestor__[0];
}

方法六

constexpr std::size_t __MAX_NODES_{ 50001U };
constexpr std::size_t __MAX_EDGES_{ 50000U };
constexpr std::size_t __MAX_DEPTH_{ 1 << 4 | 1 };

typedef struct {
	int32_t __forward__; //forward adjacent node
	int32_t __next__; //next edge
} edge;

typedef struct {
	uint32_t __enter__;
	uint32_t __leave__;
	uint32_t __depth__;
	uint32_t __distance__;
	int32_t __ancestor__[__MAX_NODES_];
} node;

int32_t head[__MAX_NODES_];
edge edges[__MAX_EDGES_];
node nodes[__MAX_NODES_];
uint32_t tot {};
uint32_t time_stamp {};

void insert(uint32_t u, uint32_t v){
//__COMMENT__: insert a edge from u to v
	edges[tot] = edge{ __forward__ : v, __next__ : head[u] };
	head[u] = tot ++;
}

inline void __init__(void){
//__COMMENT__: init the head of all edges
	std::memset(head, -1, sizeof head);
}

void dfs(int32_t u, int32_t fa){
//__COMMENT__: to mark time stamp and record depth& levelled-ancestor
	nodes[u].__enter__ = ++time_stamp;
	nodes[u].__ancestor__[0] = fa;
	if(fa) nodes[u].__depth__ = nodes[fa].__depth__ + 1;
	for(auto i {1U}; (1U << i) < nodes[u].__depth__; ++i)
		nodes[u].__ancestor__[i] = nodes[nodes[u].__ancestor__[i-1]].__ancestor__[i-1];
	for(auto i {head[u]}; ~i; i = edges[i].__next__)
		if(!(edges[i].__forward__ == fa)){
			nodes[edges[i].__forward__].__distance__ = nodes[u].__distance__ + 1;
			dfs(edges[i].__forward__, u);
		}
	nodes[u].__leave__ = ++time_stamp;
}

inline bool ancestor_validate(int32_t u, int32_t v){
//__COMMENT__: function to validate node u is whether or not node v's ancestor
	return nodes[u].__enter__ <= nodes[v].__enter__
		&& nodes[u].__leave__ >= nodes[v].__leave__;
}

int32_t lca(int32_t u, int32_t v){
//__COMMENT__: calculate lca between node u and node v
	if(nodes[u].__depth__ < nodes[v].__depth__) return lca(v, u);
	if(ancestor_validate(u, v)) return u;
	for(int h { ( int )std::ceil(std::log2(nodes[u].__depth__)) + 1}; h >= 0; --h)
		if(!ancestor_validate(nodes[u].__ancestor__[h], v))
			u = nodes[u].__ancestor__[h];
	return nodes[u].__ancestor__[0];
}

inline uint32_t dist(int32_t u, int32_t v, int32_t lca){
//__COMMENT__: calculate distance of node u and node v
	return nodes[u].__distance__ + nodes[v].__distance__ - (nodes[lca].__distance__ << 1);
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XNB's Not a Beginner

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值