📌  相关文章
📜  有根树中一组节点的最低公共祖先

📅  最后修改于: 2021-09-03 14:56:30             🧑  作者: Mango

给定具有N 个节点的有根树,任务是为该树的给定节点集V找到最低公共祖先
例子:

Input:    
                   1
                /  |  \
               2   3   4
             /  \  |   |
            5   6  7   10
                  / \
                 8   9
V[] = {7, 3, 8, 9}
Output: 3

Input:   
                   1
                /  |  \
               2   3   4
             /  \  |   |
            5   6  7   10
                  / \
                 8   9
V[] = {4, 6, 7}
Output: 1

方法:我们可以观察到

  1. 任何节点集的最低公共祖先的入时间小于或等于该集中所有节点的时间,而出时间大于或等于(如果该集合中存在 LCA 则等于)中所有节点的时间集。
  2. 因此,为了解决这个问题,我们需要使用深度优先搜索遍历从根节点开始遍历整个树,并存储每个节点的输入时间、输出时间和级别。
  3. 输入时间小于或等于集合中所有节点且输出时间大于或等于集合中所有节点且具有最大可能级别的节点是答案。

下面是上述方法的实现:

C++
// C++ Program to find the LCA
// in a rooted tree for a given
// set of nodes
 
#include 
using namespace std;
 
// Set time 1 initially
int T = 1;
void dfs(int node, int parent,
         vector g[],
         int level[], int t_in[],
         int t_out[])
{
 
    // Case for root node
    if (parent == -1) {
        level[node] = 1;
    }
    else {
        level[node] = level[parent] + 1;
    }
 
    // In-time for node
    t_in[node] = T;
    for (auto i : g[node]) {
        if (i != parent) {
            T++;
            dfs(i, node, g,
                level, t_in, t_out);
        }
    }
    T++;
 
    // Out-time for the node
    t_out[node] = T;
}
 
int findLCA(int n, vector g[],
            vector v)
{
 
    // level[i]--> Level of node i
    int level[n + 1];
 
    // t_in[i]--> In-time of node i
    int t_in[n + 1];
 
    // t_out[i]--> Out-time of node i
    int t_out[n + 1];
 
    // Fill the level, in-time
    // and out-time of all nodes
    dfs(1, -1, g,
        level, t_in, t_out);
 
    int mint = INT_MAX, maxt = INT_MIN;
    int minv = -1, maxv = -1;
    for (auto i = v.begin(); i != v.end(); i++) {
        // To find minimum in-time among
        // all nodes in LCA set
        if (t_in[*i] < mint) {
            mint = t_in[*i];
            minv = *i;
        }
        // To find maximum in-time among
        // all nodes in LCA set
        if (t_out[*i] > maxt) {
            maxt = t_out[*i];
            maxv = *i;
        }
    }
 
    // Node with same minimum
    // and maximum out time
    // is LCA for the set
    if (minv == maxv) {
        return minv;
    }
 
    // Take the minimum level as level of LCA
    int lev = min(level[minv], level[maxv]);
    int node, l = INT_MIN;
    for (int i = 1; i <= n; i++) {
        // If i-th node is at a higher level
        // than that of the minimum among
        // the nodes of the given set
        if (level[i] > lev)
            continue;
 
        // Compare in-time, out-time
        // and level of i-th node
        // to the respective extremes
        // among all nodes of the given set
        if (t_in[i] <= mint
            && t_out[i] >= maxt
            && level[i] > l) {
            node = i;
            l = level[i];
        }
    }
 
    return node;
}
 
// Driver code
int main()
{
    int n = 10;
    vector g[n + 1];
    g[1].push_back(2);
    g[2].push_back(1);
    g[1].push_back(3);
    g[3].push_back(1);
    g[1].push_back(4);
    g[4].push_back(1);
    g[2].push_back(5);
    g[5].push_back(2);
    g[2].push_back(6);
    g[6].push_back(2);
    g[3].push_back(7);
    g[7].push_back(3);
    g[4].push_back(10);
    g[10].push_back(4);
    g[8].push_back(7);
    g[7].push_back(8);
    g[9].push_back(7);
    g[7].push_back(9);
 
    vector v = { 7, 3, 8 };
 
    cout << findLCA(n, g, v) << endl;
}


Java
// Java Program to find the LCA
// in a rooted tree for a given
// set of nodes
import java.util.*;
class GFG
{
 
// Set time 1 initially
static int T = 1;
static void dfs(int node, int parent,
         Vector g[],
         int level[], int t_in[],
         int t_out[])
{
 
    // Case for root node
    if (parent == -1)
    {
        level[node] = 1;
    }
    else
    {
        level[node] = level[parent] + 1;
    }
 
    // In-time for node
    t_in[node] = T;
    for (int i : g[node])
    {
        if (i != parent)
        {
            T++;
            dfs(i, node, g,
                level, t_in, t_out);
        }
    }
    T++;
 
    // Out-time for the node
    t_out[node] = T;
}
 
static int findLCA(int n, Vector g[],
            Vector v)
{
 
    // level[i]-. Level of node i
    int []level = new int[n + 1];
 
    // t_in[i]-. In-time of node i
    int []t_in = new int[n + 1];
 
    // t_out[i]-. Out-time of node i
    int []t_out = new int[n + 1];
 
    // Fill the level, in-time
    // and out-time of all nodes
    dfs(1, -1, g,
        level, t_in, t_out);
 
    int mint = Integer.MAX_VALUE, maxt = Integer.MIN_VALUE;
    int minv = -1, maxv = -1;
    for (int i =0; i  maxt)
        {
            maxt = t_out[v.get(i)];
            maxv = v.get(i);
        }
    }
 
    // Node with same minimum
    // and maximum out time
    // is LCA for the set
    if (minv == maxv)
    {
        return minv;
    }
 
    // Take the minimum level as level of LCA
    int lev = Math.min(level[minv], level[maxv]);
    int node = 0, l = Integer.MIN_VALUE;
    for (int i = 1; i <= n; i++)
    {
       
        // If i-th node is at a higher level
        // than that of the minimum among
        // the nodes of the given set
        if (level[i] > lev)
            continue;
 
        // Compare in-time, out-time
        // and level of i-th node
        // to the respective extremes
        // among all nodes of the given set
        if (t_in[i] <= mint
            && t_out[i] >= maxt
            && level[i] > l)
        {
            node = i;
            l = level[i];
        }
    }
 
    return node;
}
 
// Driver code
public static void main(String[] args)
{
    int n = 10;
    Vector []g = new Vector[n + 1];
    for (int i = 0; i < g.length; i++)
        g[i] = new Vector();
    g[1].add(2);
    g[2].add(1);
    g[1].add(3);
    g[3].add(1);
    g[1].add(4);
    g[4].add(1);
    g[2].add(5);
    g[5].add(2);
    g[2].add(6);
    g[6].add(2);
    g[3].add(7);
    g[7].add(3);
    g[4].add(10);
    g[10].add(4);
    g[8].add(7);
    g[7].add(8);
    g[9].add(7);
    g[7].add(9);
    Vector v = new Vector<>();
    v.add(7);
    v.add(3);
    v.add(8);
    System.out.print(findLCA(n, g, v) +"\n");
}
}
 
// This code is contributed by aashish1995.


Python3
# Python Program to find the LCA
# in a rooted tree for a given
# set of nodes
from typing import List
from sys import maxsize
INT_MAX = maxsize
INT_MIN = -maxsize
 
# Set time 1 initially
T = 1
 
def dfs(node: int, parent: int, g: List[List[int]], level: List[int],
        t_in: List[int], t_out: List[int]) -> None:
    global T
     
    # Case for root node
    if (parent == -1):
        level[node] = 1
    else:
        level[node] = level[parent] + 1
 
    # In-time for node
    t_in[node] = T
    for i in g[node]:
        if (i != parent):
            T += 1
            dfs(i, node, g, level, t_in, t_out)
    T += 1
 
    # Out-time for the node
    t_out[node] = T
 
def findLCA(n: int, g: List[List[int]], v: List[int]) -> int:
 
    # level[i]--> Level of node i
    level = [0 for _ in range(n + 1)]
 
    # t_in[i]--> In-time of node i
    t_in = [0 for _ in range(n + 1)]
 
    # t_out[i]--> Out-time of node i
    t_out = [0 for _ in range(n + 1)]
 
    # Fill the level, in-time
    # and out-time of all nodes
    dfs(1, -1, g, level, t_in, t_out)
    mint = INT_MAX
    maxt = INT_MIN
    minv = -1
    maxv = -1
    for i in v:
       
        # To find minimum in-time among
        # all nodes in LCA set
        if (t_in[i] < mint):
            mint = t_in[i]
            minv = i
 
        # To find maximum in-time among
        # all nodes in LCA set
        if (t_out[i] > maxt):
            maxt = t_out[i]
            maxv = i
 
    # Node with same minimum
    # and maximum out time
    # is LCA for the set
    if (minv == maxv):
        return minv
 
    # Take the minimum level as level of LCA
    lev = min(level[minv], level[maxv])
    node = 0
    l = INT_MIN
    for i in range(n):
       
        # If i-th node is at a higher level
        # than that of the minimum among
        # the nodes of the given set
        if (level[i] > lev):
            continue
 
        # Compare in-time, out-time
        # and level of i-th node
        # to the respective extremes
        # among all nodes of the given set
        if (t_in[i] <= mint and t_out[i] >= maxt and level[i] > l):
            node = i
            l = level[i]
    return node
 
# Driver code
if __name__ == "__main__":
    n = 10
    g = [[] for _ in range(n + 1)]
    g[1].append(2)
    g[2].append(1)
    g[1].append(3)
    g[3].append(1)
    g[1].append(4)
    g[4].append(1)
    g[2].append(5)
    g[5].append(2)
    g[2].append(6)
    g[6].append(2)
    g[3].append(7)
    g[7].append(3)
    g[4].append(10)
    g[10].append(4)
    g[8].append(7)
    g[7].append(8)
    g[9].append(7)
    g[7].append(9)
 
    v = [7, 3, 8]
    print(findLCA(n, g, v))
 
# This code is contributed by sanjeev2552


C#
// C# Program to find the LCA
// in a rooted tree for a given
// set of nodes
using System;
using System.Collections.Generic;
public class GFG
{
 
  // Set time 1 initially
  static int T = 1;
  static void dfs(int node, int parent,
                  List []g,
                  int []level, int []t_in,
                  int []t_out)
  {
 
    // Case for root node
    if (parent == -1)
    {
      level[node] = 1;
    }
    else
    {
      level[node] = level[parent] + 1;
    }
 
    // In-time for node
    t_in[node] = T;
    foreach (int i in g[node])
    {
      if (i != parent)
      {
        T++;
        dfs(i, node, g,
            level, t_in, t_out);
      }
    }
    T++;
 
    // Out-time for the node
    t_out[node] = T;
  }
 
  static int findLCA(int n, List []g,
                     List v)
  {
 
    // level[i]-. Level of node i
    int []level = new int[n + 1];
 
    // t_in[i]-. In-time of node i
    int []t_in = new int[n + 1];
 
    // t_out[i]-. Out-time of node i
    int []t_out = new int[n + 1];
 
    // Fill the level, in-time
    // and out-time of all nodes
    dfs(1, -1, g,
        level, t_in, t_out);
 
    int mint = int.MaxValue, maxt = int.MinValue;
    int minv = -1, maxv = -1;
    for (int i = 0; i < v.Count; i++)
    {
 
      // To find minimum in-time among
      // all nodes in LCA set
      if (t_in[v[i]] < mint)
      {
        mint = t_in[v[i]];
        minv = v[i];
      }
 
      // To find maximum in-time among
      // all nodes in LCA set
      if (t_out[v[i]] > maxt)
      {
        maxt = t_out[v[i]];
        maxv = v[i];
      }
    }
 
    // Node with same minimum
    // and maximum out time
    // is LCA for the set
    if (minv == maxv)
    {
      return minv;
    }
 
    // Take the minimum level as level of LCA
    int lev = Math.Min(level[minv], level[maxv]);
    int node = 0, l = int.MinValue;
    for (int i = 1; i <= n; i++)
    {
 
      // If i-th node is at a higher level
      // than that of the minimum among
      // the nodes of the given set
      if (level[i] > lev)
        continue;
 
      // Compare in-time, out-time
      // and level of i-th node
      // to the respective extremes
      // among all nodes of the given set
      if (t_in[i] <= mint
          && t_out[i] >= maxt
          && level[i] > l)
      {
        node = i;
        l = level[i];
      }
    }
    return node;
  }
 
  // Driver code
  public static void Main(String[] args)
  {
    int n = 10;
    List []g = new List[n + 1];
    for (int i = 0; i < g.Length; i++)
      g[i] = new List();
    g[1].Add(2);
    g[2].Add(1);
    g[1].Add(3);
    g[3].Add(1);
    g[1].Add(4);
    g[4].Add(1);
    g[2].Add(5);
    g[5].Add(2);
    g[2].Add(6);
    g[6].Add(2);
    g[3].Add(7);
    g[7].Add(3);
    g[4].Add(10);
    g[10].Add(4);
    g[8].Add(7);
    g[7].Add(8);
    g[9].Add(7);
    g[7].Add(9);
    List v = new List();
    v.Add(7);
    v.Add(3);
    v.Add(8);
    Console.Write(findLCA(n, g, v) +"\n");
  }
}
 
// This code is contributed by Rajput-Ji


输出:

3

时间复杂度: O(N)
空间复杂度: O(N)

如果您想与行业专家一起参加直播课程,请参阅Geeks Classes Live