Shortest distance between two nodes in an infinite binary tree
Last Updated :
30 Aug, 2022
Consider you have an infinitely long binary tree having a pattern as below:
1
/ \
2 3
/ \ / \
4 5 6 7
/ \ / \ / \ / \
. . . . . . . .
Given two nodes with values x and y. The task is to find the length of the shortest path between the two nodes.
Examples:
Input: x = 2, y = 3
Output: 2
Input: x = 4, y = 6
Output: 4
A naive approach is to store all the ancestors of both nodes in 2 Data-structures(vectors, arrays, etc..) and do a binary search for the first element(let index i) in vector1, and check if it exists in the vector2 or not. If it does, return the index(let x) of the element in vector2.
The answer will be thus
distance = v1.size() – 1 – i + v2.size() – 1 – x
Below is the implementation of the above approach.
C++
#include <bits/stdc++.h>
using namespace std;
vector< int > v1;
vector< int > v2;
int BinarySearch( int x)
{
int low = 0;
int high = v2.size() - 1;
while (low <= high) {
int mid = (low + high) / 2;
if (v2[mid] == x)
return mid;
else if (v2[mid] > x)
high = mid - 1;
else
low = mid + 1;
}
return -1;
}
void MakeAncestorNode1( int x)
{
v1.clear();
while (x) {
v1.push_back(x);
x /= 2;
}
reverse(v1.begin(), v1.end());
}
void MakeAncestorNode2( int x)
{
v2.clear();
while (x) {
v2.push_back(x);
x /= 2;
}
reverse(v2.begin(), v2.end());
}
int Distance()
{
for ( int i = v1.size() - 1; i >= 0; i--) {
int x = BinarySearch(v1[i]);
if (x != -1) {
return v1.size() - 1 - i + v2.size() - 1 - x;
}
}
}
int main()
{
int node1 = 2, node2 = 3;
MakeAncestorNode1(node1);
MakeAncestorNode2(node2);
cout << "Distance between " << node1 <<
" and " << node2 << " is : " << Distance();
return 0;
}
|
Java
import java.util.*;
class GFG
{
static Vector<Integer> v1 = new Vector<Integer>();
static Vector<Integer> v2 = new Vector<Integer>();
static int BinarySearch( int x)
{
int low = 0 ;
int high = v2.size() - 1 ;
while (low <= high)
{
int mid = (low + high) / 2 ;
if (v2.get(mid) == x)
return mid;
else if (v2.get(mid) > x)
high = mid - 1 ;
else
low = mid + 1 ;
}
return - 1 ;
}
static void MakeAncestorNode1( int x)
{
v1.clear();
while (x > 0 )
{
v1.add(x);
x /= 2 ;
}
Collections.reverse(v1);
}
static void MakeAncestorNode2( int x)
{
v2.clear();
while (x > 0 )
{
v2.add(x);
x /= 2 ;
}
Collections.reverse(v2);
}
static int Distance()
{
for ( int i = v1.size() - 1 ; i >= 0 ; i--)
{
int x = BinarySearch(v1.get(i));
if (x != - 1 )
{
return v1.size() - 1 - i +
v2.size() - 1 - x;
}
}
return Integer.MAX_VALUE;
}
public static void main(String[] args)
{
int node1 = 2 , node2 = 3 ;
MakeAncestorNode1(node1);
MakeAncestorNode2(node2);
System.out.print( "Distance between " + node1 +
" and " + node2 + " is : " +
Distance());
}
}
|
Python3
def BinarySearch(x):
low = 0
high = len (v2) - 1
while low < = high:
mid = (low + high) / / 2
if v2[mid] = = x:
return mid
elif v2[mid] > x:
high = mid - 1
else :
low = mid + 1
return - 1
def MakeAncestorNode1(x):
v1.clear()
while x:
v1.append(x)
x / / = 2
v1.reverse()
def MakeAncestorNode2(x):
v2.clear()
while x:
v2.append(x)
x / / = 2
v2.reverse()
def Distance():
for i in range ( len (v1) - 1 , - 1 , - 1 ):
x = BinarySearch(v1[i])
if x ! = - 1 :
return ( len (v1) - 1 - i +
len (v2) - 1 - x)
if __name__ = = "__main__" :
node1, node2 = 2 , 3
v1, v2 = [], []
MakeAncestorNode1(node1)
MakeAncestorNode2(node2)
print ( "Distance between" , node1,
"and" , node2, "is :" , Distance())
|
C#
using System;
using System.Collections.Generic;
class GFG
{
static List< int > v1 = new List< int >();
static List< int > v2 = new List< int >();
static int BinarySearch( int x)
{
int low = 0;
int high = v2.Count - 1;
while (low <= high)
{
int mid = (low + high) / 2;
if (v2[mid] == x)
return mid;
else if (v2[mid] > x)
high = mid - 1;
else
low = mid + 1;
}
return -1;
}
static void MakeAncestorNode1( int x)
{
v1.Clear();
while (x > 0)
{
v1.Add(x);
x /= 2;
}
v1.Reverse();
}
static void MakeAncestorNode2( int x)
{
v2.Clear();
while (x > 0)
{
v2.Add(x);
x /= 2;
}
v2.Reverse();
}
static int Distance()
{
for ( int i = v1.Count - 1; i >= 0; i--)
{
int x = BinarySearch(v1[i]);
if (x != -1)
{
return v1.Count - 1 - i +
v2.Count - 1 - x;
}
}
return int .MaxValue;
}
public static void Main(String[] args)
{
int node1 = 2, node2 = 3;
MakeAncestorNode1(node1);
MakeAncestorNode2(node2);
Console.Write( "Distance between " + node1 +
" and " + node2 + " is : " +
Distance());
}
}
|
Javascript
<script>
let v1 = [];
let v2 = [];
function BinarySearch(x)
{
let low = 0;
let high = v2.length - 1;
while (low <= high)
{
let mid = Math.floor((low + high) / 2);
if (v2[mid] == x)
return mid;
else if (v2[mid] > x)
high = mid - 1;
else
low = mid + 1;
}
return -1;
}
function MakeAncestorNode1(x)
{
v1=[];
while (x > 0)
{
v1.push(x);
x = Math.floor(x/2);
}
v1.reverse();
}
function MakeAncestorNode2(x)
{
v2=[];
while (x > 0)
{
v2.push(x);
x = Math.floor(x/2);
}
v2.reverse();
}
function Distance()
{
for (let i = v1.length - 1; i >= 0; i--)
{
let x = BinarySearch(v1[i]);
if (x != -1)
{
return v1.length - 1 - i +
v2.length - 1 - x;
}
}
return Number.MAX_VALUE;
}
let node1 = 2, node2 = 3;
MakeAncestorNode1(node1);
MakeAncestorNode2(node2);
document.write( "Distance between " + node1 +
" and " + node2 + " is : " +
Distance());
</script>
|
Output
Distance between 2 and 3 is : 2
Complexity Analysis:
- Time Complexity: O(log(max(x, y)) * log(max(x, y)))
- Auxiliary Space: O(log(max(x, y)))
An efficient approach is to use the property of 2*x and 2*x+1 given. Keep dividing the larger of the two nodes by 2. If the larger becomes the smaller one, then divide the other one. At a stage, both the values will be the same, keep a count on the number of divisions done which will be the answer.
Below is the implementation of the above approach.
C++
#include <bits/stdc++.h>
using namespace std;
int Distance( int x, int y)
{
if (x < y) {
swap(x, y);
}
int c = 0;
while (x != y) {
++c;
if (x > y)
x = x >> 1;
if (y > x) {
y = y >> 1;
++c;
}
}
return c;
}
int main()
{
int x = 4, y = 6;
cout << Distance(x, y);
return 0;
}
|
Java
class GFG
{
static int Distance( int x, int y)
{
if (x < y)
{
int temp = x;
x = y;
y = temp;
}
int c = 0 ;
while (x != y)
{
++c;
if (x > y)
x = x >> 1 ;
if (y > x)
{
y = y >> 1 ;
++c;
}
}
return c;
}
public static void main(String[] args)
{
int x = 4 , y = 6 ;
System.out.println(Distance(x, y));
}
}
|
Python3
def Distance(x, y):
if x < y:
x, y = y, x
c = 0
while x ! = y:
c + = 1
if x > y:
x = x >> 1
if y > x:
y = y >> 1
c + = 1
return c
if __name__ = = "__main__" :
x, y = 4 , 6
print (Distance(x, y))
|
C#
using System;
class GFG
{
static int Distance( int x, int y)
{
if (x < y)
{
int temp = x;
x = y;
y = temp;
}
int c = 0;
while (x != y)
{
++c;
if (x > y)
x = x >> 1;
if (y > x)
{
y = y >> 1;
++c;
}
}
return c;
}
public static void Main(String[] args)
{
int x = 4, y = 6;
Console.WriteLine(Distance(x, y));
}
}
|
Javascript
<script>
function Distance(x, y)
{
if (x < y)
{
let temp = x;
x = y;
y = temp;
}
let c = 0;
while (x != y)
{
++c;
if (x > y)
x = x >> 1;
if (y > x)
{
y = y >> 1;
++c;
}
}
return c;
}
let x = 4, y = 6;
document.write(Distance(x, y));
</script>
|
Complexity Analysis:
- Time Complexity: O(log(max(x, y)))
- Auxiliary Space: O(1)
The efficient approach has been suggested by Striver.
Another Approach:
The main idea is to use the formula Level(n) + Level(m) – 2* LCA(n,m) . So Level can easily be calculated using Log base 2 and LCA can be calculated by dividing the greater No. by 2 until n and m become equal.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int LCA( int n, int m)
{
if (n > m) {
swap(n, m);
}
int a = log2(n);
int b = log2(m);
while (n != m)
{
if (n < m)
m = m >> 1;
if (n > m)
n = n >> 1;
}
int v = log2(n);
return a + b - 2 * v;
}
int main()
{
int n = 2, m = 6;
cout << LCA(n,m) << endl;
return 0;
}
|
Java
import java.util.*;
class GFG{
static int LCA( int n, int m)
{
if (n > m) {
int temp = n;
n = m;
m = temp;
}
int a = ( int )(Math.log(n) / Math.log( 2 ));
int b = ( int )(Math.log(m) / Math.log( 2 ));
while (n != m)
{
if (n < m)
m = m >> 1 ;
if (n > m)
n = n >> 1 ;
}
int v = ( int )(Math.log(n) / Math.log( 2 ));
return a + b - 2 * v;
}
public static void main(String[] args)
{
int n = 2 , m = 6 ;
System.out.print(LCA(n,m) + "\n" );
}
}
|
Python3
import math
def LCA(n, m):
if (n > m):
n, m = m, n
a = int (math.log2(n))
b = int (math.log2(m))
while (n ! = m):
if (n < m):
m = m >> 1
if (n > m):
n = n >> 1
v = int (math.log2(n))
return a + b - 2 * v
n = 2
m = 6
print (LCA(n,m))
|
C#
using System;
class GFG{
static int LCA( int n, int m)
{
if (n > m) {
int temp = n;
n = m;
m = temp;
}
int a = ( int )(Math.Log(n) / Math.Log(2));
int b = ( int )(Math.Log(m) / Math.Log(2));
while (n != m)
{
if (n < m)
m = m >> 1;
if (n > m)
n = n >> 1;
}
int v = ( int )(Math.Log(n) / Math.Log(2));
return a + b - 2 * v;
}
public static void Main(String[] args)
{
int n = 2, m = 6;
Console.Write(LCA(n,m) + "\n" );
}
}
|
Javascript
<script>
function LCA(n, m)
{
if (n > m)
{
let temp = n;
n = m;
m = temp;
}
let a = Math.log2(n);
let b = Math.log2(m);
while (n != m)
{
if (n < m)
m = m >> 1;
if (n > m)
n = n >> 1;
}
let v = Math.log2(n);
return a + b - 2 * v;
}
let n = 2, m = 6;
document.write(LCA(n, m));
</script>
|
Complexity Analysis:
- Time Complexity: O(log(max(x, y)))
- Auxiliary Space: O(1)
Share your thoughts in the comments
Please Login to comment...