Проверить, находится ли данный узел на пути между узлами U и V

Опубликовано: 12 Января, 2022

Для трех вершин U , V и R двоичного дерева задача состоит в том, чтобы проверить, лежит ли R на пути между U и V. Если его нет в пути, выведите « Нет», в противном случае выведите « Да» .
Примеры:

Input: U = 4, V = 6, R = 2 
 

Output: Yes 
Path 4 -> 2 -> 1 -> 3 -> 6 contains 2
Input: U = 4, V = 6, R = 5 
 

Output: No 
Path 4 -> 2 -> 1 -> 3 -> 6 does not contain 5 
 

Рекомендуется: сначала попробуйте свой подход в {IDE}, прежде чем переходить к решению.

Подход: идея состоит в том, чтобы использовать наименьшего общего предка двух узлов. R существует на пути между U и V в следующих случаях:

  1. R - самый низкий общий предок U и V.

  1. R находится в левом поддереве самого низкого общего предка U и V и находится выше V.

  1. R находится в правом поддереве самого низкого общего предка U и V и находится выше U.

To know more about the lowest commom ancestor, read the post here.
Below is the implementation of the above approach: 
 

C++

// CPP Program to implement the above appraoch
#include <bits/stdc++.h>
using namespace std;
 
class GfG
{
  public:
 
  // Table for storing 2^ith parent
  vector<vector<int>> table;
 
  // Variable to store the height of the tree
  int height;
 
  // Graph
  vector<vector<int>> Graph;
 
  // Arrays to mark start and end time for a node
  vector<int> timeIn, timeOut;
 
  // Timer
  int time;
 
  // constructor for initializing
  // the global variables
  GfG(int n)
  {
 
    // log(n) with base 2
    height = (int)ceil(log2(n));
 
    // Filling with -1 as initial
    table.resize(n + 1, vector<int>(height + 1, -1));
 
    // Fill the graph with empty lists
    Graph.resize(n + 1);
    timeIn.resize(n + 1);
    timeOut.resize(n + 1);
    time = 0;
  }
 
  // Dfs for pre-processing sparse table and
  // calculating start and end time
  void dfs(int s, int p)
  {
 
    // Parent at 1 node distance is always
    // it"s direct parent
    table[s][0] = p;
 
    // Start time noted
    timeIn[s] = ++time;
 
    // Filling sparse table recursively
    for (int i = 1; i <= height; i++)
      table[s][i] = table[table[s][i - 1]][i - 1];
 
    // Traversing children of source
    for (int child : Graph[s]) {
      if (child == p) continue;
      dfs(child, s);
    }
 
    // End time noted
    timeOut[s] = ++time;
  }
 
  // Helper function to check lowest common Ancestor
  bool check(int u, int v)
  {
    return timeIn[u] <= timeIn[v] && timeOut[u] >= timeOut[v];
  }
 
  // Function to return Lowest Common Ancestor of U and V
  int lowestCommonAncestor(int U, int V)
  {
    if (check(U, V)) return U;
 
    if (check(V, U)) return V;
 
    for (int i = height; i >= 0; i--)
    {
      if (!check(table[U][i], V)) U = table[U][i];
    }
 
    return table[U][0];
  }
 
  // Function that return true if R
  // exists on the path between U
  // and V in the given tree
  bool isPresent(int U, int V, int R)
  {
 
    // Dfs
    dfs(1, 1);
 
    // Calculating LCA between U and V
    int LCA = lowestCommonAncestor(U, V);
 
    // Calculating LCA between U and R
    int LCA_1 = lowestCommonAncestor(U, R);
 
    // Calculating LCA between U and V
    int LCA_2 = lowestCommonAncestor(V, R);
 
    if (LCA == R || (LCA_1 == LCA && LCA_2 == R) ||
        (LCA_2 == LCA && LCA_1 == R)) {
      return true;
    }
    return false;
  }
};
 
// Driver code
int main(int argc, char const *argv[])
{
 
  // Number of vertices
  int n = 6;
  GfG *obj = new GfG(n);
 
  // Create the graph
  obj->Graph[1].push_back(2);
  obj->Graph[2].push_back(1);
  obj->Graph[1].push_back(3);
  obj->Graph[3].push_back(1);
  obj->Graph[2].push_back(4);
  obj->Graph[4].push_back(2);
  obj->Graph[2].push_back(5);
  obj->Graph[5].push_back(2);
  obj->Graph[3].push_back(6);
  obj->Graph[6].push_back(3);
 
  int U = 4, V = 6, R = 2;
  if (obj->isPresent(U, V, R))
    cout << "Yes" << endl;
  else
    cout << "No" << endl;
}
 
// This code is contributed by sanjeev2552

Java

// Java implementation of the approach
import java.util.*;
 
class GfG {
 
    // Table for storing 2^ith parent
    private static int table[][];
 
    // Variable to store the height of the tree
    private static int height;
 
    // Graph
    private static ArrayList<ArrayList<Integer> > Graph;
 
    // Arrays to mark start and end time for a node
    private static int timeIn[];
    private static int timeOut[];
 
    // Timer
    private static int time;
 
    // Private constructor for initializing
    // the global variables
    private GfG(int n)
    {
 
        // log(n) with base 2
        height = (int)Math.ceil(Math.log10(n) / Math.log10(2));
        table = new int[n + 1][height + 1];
 
        // Fill the graph with empty lists
        Graph = new ArrayList<ArrayList<Integer> >();
        for (int i = 0; i <= n; i++)
            Graph.add(new ArrayList<Integer>());
        timeIn = new int[n + 1];
        timeOut = new int[n + 1];
        time = 0;
    }
 
    // Filling with -1 as initial
    private static void preprocessing(int n)
    {
        for (int i = 0; i < n + 1; i++) {
            Arrays.fill(table[i], -1);
        }
    }
 
    // Dfs for pre-processing sparse table and
    // calculating start and end time
    private static void dfs(int s, int p)
    {
        // Parent at 1 node distance is always
        // it"s direct parent
        table[s][0] = p;
 
        // Start time noted
        timeIn[s] = ++time;
 
        // Filling sparse table recursively
        for (int i = 1; i <= height; i++)
            table[s][i] = table[table[s][i - 1]][i - 1];
 
        // Traversing children of source
        for (int child : Graph.get(s)) {
            if (child == p)
                continue;
            dfs(child, s);
        }
 
        // End time noted
        timeOut[s] = ++time;
    }
 
    // Helper function to check lowest common Ancestor
    private static boolean check(int u, int v)
    {
        return timeIn[u] <= timeIn[v] && timeOut[u] >= timeOut[v];
    }
 
    // Function to return Lowest Common Ancestor of U and V
    private static int lowestCommonAncestor(int U, int V)
    {
        if (check(U, V))
            return U;
 
        if (check(V, U))
            return V;
 
        for (int i = height; i >= 0; i--) {
            if (!check(table[U][i], V))
                U = table[U][i];
        }
 
        return table[U][0];
    }
 
    // Function that return true if R
    // exists on the path between U
    // and V in the given tree
    private static boolean isPresent(int U, int V, int R)
    {
 
        // Dfs
        dfs(1, 1);
 
        // Calculating LCA between U and V
        int LCA = lowestCommonAncestor(U, V);
 
        // Calculating LCA between U and R
        int LCA_1 = lowestCommonAncestor(U, R);
 
        // Calculating LCA between U and V
        int LCA_2 = lowestCommonAncestor(V, R);
 
        if (LCA == R || (LCA_1 == LCA && LCA_2 == R)
            || (LCA_2 == LCA && LCA_1 == R)) {
            return true;
        }
        return false;
    }
 
    // Driver code
    public static void main(String args[])
    {
        // Number of vertices
        int n = 6;
        GfG obj = new GfG(n);
 
        // Create the graph
        preprocessing(n);
        Graph.get(1).add(2);
        Graph.get(2).add(1);
        Graph.get(1).add(3);
        Graph.get(3).add(1);
        Graph.get(2).add(4);
        Graph.get(4).add(2);
        Graph.get(2).add(5);
        Graph.get(5).add(2);
        Graph.get(3).add(6);
        Graph.get(6).add(3);
 
        int U = 4, V = 6, R = 2;
        if (isPresent(U, V, R))
            System.out.print("Yes");
        else
            System.out.print("No");
    }
}

C#

// C# implementation of the approach
using System;
using System.Collections.Generic;
 
class GfG
{
 
    // Table for storing 2^ith parent
    private static int [,]table;
 
    // Variable to store the height of the tree
    private static int height;
 
    // Graph
    private static List<List<int> > Graph;
 
    // Arrays to mark start and end time for a node
    private static int []timeIn;
    private static int []timeOut;
 
    // Timer
    private static int time;
 
    // Private constructor for initializing
    // the global variables
    private GfG(int n)
    {
 
        // log(n) with base 2
        height = (int)Math.Ceiling(Math.Log10(n) / Math.Log10(2));
        table = new int[n + 1, height + 1];
 
        // Fill the graph with empty lists
        Graph = new List<List<int> >();
        for (int i = 0; i <= n; i++)
            Graph.Add(new List<int>());
        timeIn = new int[n + 1];
        timeOut = new int[n + 1];
        time = 0;
    }
 
    // Filling with -1 as initial
    private static void preprocessing(int n)
    {
        for (int i = 0; i < n + 1; i++)
        {
            for(int j = 0; j < height + 1; j++)
                table[i, j] = -1;
        }
    }
 
    // Dfs for pre-processing sparse table and
    // calculating start and end time
    private static void dfs(int s, int p)
    {
        // Parent at 1 node distance is always
        // it"s direct parent
        table[s, 0] = p;
 
        // Start time noted
        timeIn[s] = ++time;
 
        // Filling sparse table recursively
        for (int i = 1; i <= height; i++)
            table[s, i] = table[table[s, i - 1], i - 1];
 
        // Traversing children of source
        foreach (int child in Graph[s])
        {
            if (child == p)
                continue;
            dfs(child, s);
        }
 
        // End time noted
        timeOut[s] = ++time;
    }
 
    // Helper function to check lowest common Ancestor
    private static bool check(int u, int v)
    {
        return timeIn[u] <= timeIn[v] && timeOut[u] >= timeOut[v];