Number of turns to reach from one node to other in binary tree
Last Updated : 20 Aug, 2026
Given root of a binary tree and the values of its two nodes p and q, count turns required to travel from node p to q.
A turn occurs whenever the direction of movement changes from left to right or right to left while traversing the tree.
If the path between the two nodes does not involve any turns (i.e., the nodes lie on the same straight path), return -1.
Note:Â All node values are distinct.
Examples:Â
Input: root[] = [1, 2, 3, 4, 5, 6, 7, 8, N, N, N, 9, 10], p = 5, q = 10
Output: 4 Explanation: The path from node 5 to node 10 is: 5 -> 2 -> 1 -> 3 -> 6 â 10. Direction changes occur at nodes 2, 1, 3, and 6. Therefore, the number of turns is 4.
Input: root[] = [1, 2, 3, 4, 5, 6, 7, 8, N, N, N, 9, 10], p = 1, q = 4
Output: -1 Explanation: No turn is required since they are in a straight line.
[Naive Approach] Find Complete Path - O(n) Time and O(n) Space
The idea is to find the path from the root to both p and q.
Combine these paths to construct the complete path from p to q.
After that, we check every consecutive pair and count whenever the direction changes from left to right or right to left.
Working of the Approach:
Find the path from root to p and root to q.
Find their common path to identify the LCA.
Construct the complete path from p to q.
For every edge, identify whether it represents a left or right direction.
Count direction changes and return -1 if there are no turns.
C++
#include<iostream>#include<vector>usingnamespacestd;classNode{public:intdata;Node*left;Node*right;Node(intval){data=val;left=right=nullptr;}};// Find path from root to the target nodeboolfindPath(Node*root,inttarget,vector<Node*>&path){if(root==nullptr)returnfalse;path.push_back(root);// Target node foundif(root->data==target)returntrue;// Search in left subtreeif(findPath(root->left,target,path))returntrue;// Search in right subtreeif(findPath(root->right,target,path))returntrue;// Remove current node if target is not foundpath.pop_back();returnfalse;}intnumberOfTurns(Node*root,intp,intq){vector<Node*>pathP,pathQ;// Find paths from root to p and qfindPath(root,p,pathP);findPath(root,q,pathQ);// Find the common part of both pathsinti=0;while(i<pathP.size()&&i<pathQ.size()&&pathP[i]==pathQ[i]){i++;}// Build complete path from p to qvector<Node*>path;// Add path from p to LCAfor(intj=pathP.size()-1;j>=i-1;j--)path.push_back(pathP[j]);// Add path from LCA to qfor(intj=i;j<pathQ.size();j++)path.push_back(pathQ[j]);intturns=0;intprevDir=0;// Count changes between left and right directionsfor(intj=0;j+1<path.size();j++){intcurrDir;// Moving from parent to left childif(path[j]->left==path[j+1])currDir=1;// Moving from parent to right childelseif(path[j]->right==path[j+1])currDir=2;// Moving from child to parentelseif(path[j+1]->left==path[j])currDir=1;elsecurrDir=2;// Direction changedif(prevDir!=0&&prevDir!=currDir)turns++;prevDir=currDir;}// If no turn is present, return -1returnturns==0?-1:turns;}intmain(){/* 1 / \ 2 3 / \ / \ 4 5 6 7 / / \ 8 9 10 p = 5 q = 10 */Node*root=newNode(1);root->left=newNode(2);root->right=newNode(3);root->left->left=newNode(4);root->left->right=newNode(5);root->right->left=newNode(6);root->right->right=newNode(7);root->left->left->left=newNode(8);root->right->left->left=newNode(9);root->right->left->right=newNode(10);intp=5;intq=10;cout<<numberOfTurns(root,p,q)<<endl;return0;}
Java
importjava.util.ArrayList;importjava.util.List;classNode{publicintdata;publicNodeleft;publicNoderight;publicNode(intval){data=val;left=right=null;}}publicclassGFG{// Find path from root to the target nodepublicstaticbooleanfindPath(Noderoot,inttarget,List<Node>path){if(root==null)returnfalse;path.add(root);// Target node foundif(root.data==target)returntrue;// Search in left subtreeif(findPath(root.left,target,path))returntrue;// Search in right subtreeif(findPath(root.right,target,path))returntrue;// Remove current node if target is not foundpath.remove(path.size()-1);returnfalse;}publicstaticintnumberOfTurns(Noderoot,intp,intq){List<Node>pathP=newArrayList<>(),pathQ=newArrayList<>();// Find paths from root to p and qfindPath(root,p,pathP);findPath(root,q,pathQ);// Find the common part of both pathsinti=0;while(i<pathP.size()&&i<pathQ.size()&&pathP.get(i)==pathQ.get(i)){i++;}// Build complete path from p to qList<Node>path=newArrayList<>();// Add path from p to LCAfor(intj=pathP.size()-1;j>=i-1;j--)path.add(pathP.get(j));// Add path from LCA to qfor(intj=i;j<pathQ.size();j++)path.add(pathQ.get(j));intturns=0;intprevDir=0;// Count changes between left and right directionsfor(intj=0;j+1<path.size();j++){intcurrDir;// Moving from parent to left childif(path.get(j).left==path.get(j+1))currDir=1;// Moving from parent to right childelseif(path.get(j).right==path.get(j+1))currDir=2;// Moving from child to parentelseif(path.get(j+1).left==path.get(j))currDir=1;elsecurrDir=2;// Direction changedif(prevDir!=0&&prevDir!=currDir)turns++;prevDir=currDir;}// If no turn is present, return -1returnturns==0?-1:turns;}publicstaticvoidmain(String[]args){Noderoot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.left=newNode(6);root.right.right=newNode(7);root.left.left.left=newNode(8);root.right.left.left=newNode(9);root.right.left.right=newNode(10);intp=5;intq=10;System.out.println(numberOfTurns(root,p,q));}}
Python
classNode:def__init__(self,val):self.data=valself.left=Noneself.right=None# Find path from root to the target nodedeffindPath(root,target,path):ifrootisNone:returnFalsepath.append(root)# Target node foundifroot.data==target:returnTrue# Search in left subtreeiffindPath(root.left,target,path):returnTrue# Search in right subtreeiffindPath(root.right,target,path):returnTrue# Remove current node if target is not foundpath.pop()returnFalsedefnumberOfTurns(root,p,q):pathP,pathQ=[],[]# Find paths from root to p and qfindPath(root,p,pathP)findPath(root,q,pathQ)# Find the common part of both pathsi=0whilei<len(pathP)andi<len(pathQ)andpathP[i]==pathQ[i]:i+=1# Build complete path from p to qpath=[]# Add path from p to LCAforjinrange(len(pathP)-1,i-2,-1):path.append(pathP[j])# Add path from LCA to qforjinrange(i,len(pathQ)):path.append(pathQ[j])turns=0prevDir=0# Count changes between left and right directionsforjinrange(len(path)-1):currDir=0# Moving from parent to left childifpath[j].left==path[j+1]:currDir=1# Moving from parent to right childelifpath[j].right==path[j+1]:currDir=2# Moving from child to parentelifpath[j+1].left==path[j]:currDir=1else:currDir=2# Direction changedifprevDir!=0andprevDir!=currDir:turns+=1prevDir=currDir# If no turn is present, return -1return-1ifturns==0elseturnsif__name__=='__main__':root=Node(1)root.left=Node(2)root.right=Node(3)root.left.left=Node(4)root.left.right=Node(5)root.right.left=Node(6)root.right.right=Node(7)root.left.left.left=Node(8)root.right.left.left=Node(9)root.right.left.right=Node(10)p=5q=10print(numberOfTurns(root,p,q))
C#
usingSystem;usingSystem.Collections.Generic;publicclassNode{publicintdata;publicNodeleft;publicNoderight;publicNode(intval){data=val;left=right=null;}}publicclassGFG{// Find path from root to the target nodepublicstaticboolfindPath(Noderoot,inttarget,List<Node>path){if(root==null)returnfalse;path.Add(root);// Target node foundif(root.data==target)returntrue;// Search in left subtreeif(findPath(root.left,target,path))returntrue;// Search in right subtreeif(findPath(root.right,target,path))returntrue;// Remove current node if target is not foundpath.RemoveAt(path.Count-1);returnfalse;}publicstaticintnumberOfTurns(Noderoot,intp,intq){List<Node>pathP=newList<Node>(),pathQ=newList<Node>();// Find paths from root to p and qfindPath(root,p,pathP);findPath(root,q,pathQ);// Find the common part of both pathsinti=0;while(i<pathP.Count&&i<pathQ.Count&&pathP[i]==pathQ[i]){i++;}// Build complete path from p to qList<Node>path=newList<Node>();// Add path from p to LCAfor(intj=pathP.Count-1;j>=i-1;j--)path.Add(pathP[j]);// Add path from LCA to qfor(intj=i;j<pathQ.Count;j++)path.Add(pathQ[j]);intturns=0;intprevDir=0;// Count changes between left and right directionsfor(intj=0;j+1<path.Count;j++){intcurrDir;// Moving from parent to left childif(path[j].left==path[j+1])currDir=1;// Moving from parent to right childelseif(path[j].right==path[j+1])currDir=2;// Moving from child to parentelseif(path[j+1].left==path[j])currDir=1;elsecurrDir=2;// Direction changedif(prevDir!=0&&prevDir!=currDir)turns++;prevDir=currDir;}// If no turn is present, return -1returnturns==0?-1:turns;}publicstaticvoidMain(){/* 1 / \ 2 3 / \ / \\ 4 5 6 7 / / \\ 8 9 10 p = 5 q = 10 */Noderoot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.left=newNode(6);root.right.right=newNode(7);root.left.left.left=newNode(8);root.right.left.left=newNode(9);root.right.left.right=newNode(10);intp=5;intq=10;Console.WriteLine(numberOfTurns(root,p,q));}}
JavaScript
classNode{constructor(val){this.data=val;this.left=null;this.right=null;}}// Find path from root to the target nodefunctionfindPath(root,target,path){if(root===null)returnfalse;path.push(root);// Target node foundif(root.data===target)returntrue;// Search in left subtreeif(findPath(root.left,target,path))returntrue;// Search in right subtreeif(findPath(root.right,target,path))returntrue;// Remove current node if target is not foundpath.pop();returnfalse;}functionnumberOfTurns(root,p,q){letpathP=[],pathQ=[];// Find paths from root to p and qfindPath(root,p,pathP);findPath(root,q,pathQ);// Find the common part of both pathsleti=0;while(i<pathP.length&&i<pathQ.length&&pathP[i]===pathQ[i]){i++;}// Build complete path from p to qletpath=[];// Add path from p to LCAfor(letj=pathP.length-1;j>=i-1;j--)path.push(pathP[j]);// Add path from LCA to qfor(letj=i;j<pathQ.length;j++)path.push(pathQ[j]);letturns=0;letprevDir=0;// Count changes between left and right directionsfor(letj=0;j+1<path.length;j++){letcurrDir;// Moving from parent to left childif(path[j].left===path[j+1])currDir=1;// Moving from parent to right childelseif(path[j].right===path[j+1])currDir=2;// Moving from child to parentelseif(path[j+1].left===path[j])currDir=1;elsecurrDir=2;// Direction changedif(prevDir!==0&&prevDir!==currDir)turns++;prevDir=currDir;}// If no turn is present, return -1returnturns===0?-1:turns;}// Driver Codeletroot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.left=newNode(6);root.right.right=newNode(7);root.left.left.left=newNode(8);root.right.left.left=newNode(9);root.right.left.right=newNode(10);letp=5;letq=10;console.log(numberOfTurns(root,p,q));
Output
4
[Expected Approach] Using LCA with Path Tracking - O(n) Time and O(n) Space
The idea is to first find the LCA of p and q, then find the paths from the LCA to both nodes using L and R.
We count direction changes in both paths.
If p and q are in different subtrees of the LCA, moving from one subtree to the other creates one additional turn.
Working of the Approach:
Find the LCA of p and q.
Find the L/R path from LCA to p and from LCA to q.
Count direction changes in both paths.
If LCA is neither p nor q, add one turn for changing subtrees at LCA.
Return -1 if the total number of turns is 0.
Let us understand with an example: Input: root[] = [1, 2, 3, 4, 5, 6, 7, 8, N, N, N, 9, 10], p = 5, q = 10
Find LCA: The LCA of nodes 5 and 10 is 1.
Find paths from LCA: Path to 5 is LR, and path to 10 is RLR.
Count turns: LR has 1 turn, while RLR has 2 turns.
Turn at LCA: Since 5 and 10 are in different subtrees of 1, add 1 extra turn.
Total: 1 + 2 + 1 = 4, so the answer is 4.
C++
#include<iostream>#include<vector>#include<string>usingnamespacestd;classNode{public:intdata;Node*left;Node*right;Node(intval){data=val;left=right=nullptr;}};// Finds LCA of two given nodesNode*findLCA(Node*root,intp,intq){if(root==nullptr)returnnullptr;if(root->data==p||root->data==q)returnroot;Node*left=findLCA(root->left,p,q);Node*right=findLCA(root->right,p,q);if(left&&right)returnroot;returnleft?left:right;}// Stores path from root to target node using L/R directionsboolfindPath(Node*root,inttarget,string&path){if(root==nullptr)returnfalse;if(root->data==target)returntrue;// Try going leftpath.push_back('L');if(findPath(root->left,target,path))returntrue;path.pop_back();// Try going rightpath.push_back('R');if(findPath(root->right,target,path))returntrue;path.pop_back();returnfalse;}// Counts direction changes in a pathintcountTurns(string&path){intturns=0;for(inti=1;i<path.length();i++){if(path[i]!=path[i-1])turns++;}returnturns;}// Returns number of turns required from first node to second nodeintnumberOfTurns(Node*root,intp,intq){Node*lca=findLCA(root,p,q);if(lca==nullptr)return-1;stringpathFirst="";stringpathSecond="";// Paths from LCA to both nodesfindPath(lca,p,pathFirst);findPath(lca,q,pathSecond);intturns=0;/* If LCA is one of the nodes, there is no extra turn at LCA because we start from that node. */if(lca->data==p||lca->data==q){stringpath=(lca->data==p)?pathSecond:pathFirst;turns=countTurns(path);}else{/* We go: first -> LCA -> second At LCA, we change direction from one subtree to another, so it contributes one turn. */turns=countTurns(pathFirst)+countTurns(pathSecond)+1;}// No turns means both nodes lie on a straight pathreturnturns==0?-1:turns;}intmain(){/* 1 / \ 2 3 / \ / \ 4 5 6 7 / / \ 8 9 10 p = 5 q = 10 */Node*root=newNode(1);root->left=newNode(2);root->right=newNode(3);root->left->left=newNode(4);root->left->right=newNode(5);root->right->left=newNode(6);root->right->right=newNode(7);root->left->left->left=newNode(8);root->right->left->left=newNode(9);root->right->left->right=newNode(10);intp=5;intq=10;cout<<numberOfTurns(root,p,q)<<endl;return0;}
Java
importjava.util.*;classNode{publicintdata;publicNodeleft;publicNoderight;publicNode(intval){data=val;left=right=null;}}publicclassGFG{// Finds LCA of two given nodesstaticNodefindLCA(Noderoot,intp,intq){if(root==null)returnnull;if(root.data==p||root.data==q)returnroot;Nodeleft=findLCA(root.left,p,q);Noderight=findLCA(root.right,p,q);if(left!=null&&right!=null)returnroot;returnleft!=null?left:right;}// Stores path from root to target node using L/R// directionsstaticbooleanfindPath(Noderoot,inttarget,StringBuilderpath){if(root==null)returnfalse;if(root.data==target)returntrue;// Try going leftpath.append('L');if(findPath(root.left,target,path))returntrue;path.deleteCharAt(path.length()-1);// Try going rightpath.append('R');if(findPath(root.right,target,path))returntrue;path.deleteCharAt(path.length()-1);returnfalse;}// Counts direction changes in a pathstaticintcountTurns(Stringpath){intturns=0;for(inti=1;i<path.length();i++){if(path.charAt(i)!=path.charAt(i-1))turns++;}returnturns;}// Returns number of turns required from first node to// second nodestaticintnumberOfTurns(Noderoot,intp,intq){Nodelca=findLCA(root,p,q);if(lca==null)return-1;StringBuilderpathFirst=newStringBuilder();StringBuilderpathSecond=newStringBuilder();// Paths from LCA to both nodesfindPath(lca,p,pathFirst);findPath(lca,q,pathSecond);intturns=0;/* If LCA is one of the nodes, there is no extra turn at LCA because we start from that node. */if(lca.data==p||lca.data==q){Stringpath=(lca.data==p)?pathSecond.toString():pathFirst.toString();turns=countTurns(path);}else{/* We go: first -> LCA -> second At LCA, we change direction from one subtree to another, so it contributes one turn. */turns=countTurns(pathFirst.toString())+countTurns(pathSecond.toString())+1;}// No turns means both nodes lie on a straight pathreturnturns==0?-1:turns;}publicstaticvoidmain(String[]args){/* 1 / \ 2 3 / \ / \ 4 5 6 7 / / \ 8 9 10 p = 5 q = 10 */Noderoot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.left=newNode(6);root.right.right=newNode(7);root.left.left.left=newNode(8);root.right.left.left=newNode(9);root.right.left.right=newNode(10);intp=5;intq=10;System.out.println(numberOfTurns(root,p,q));}}
Python
classNode:def__init__(self,val):self.data=valself.left=Noneself.right=None# Finds LCA of two given nodesdeffindLCA(root,p,q):ifrootisNone:returnNoneifroot.data==porroot.data==q:returnrootleft=findLCA(root.left,p,q)right=findLCA(root.right,p,q)ifleftandright:returnrootreturnleftifleftelseright# Stores path from root to target node using L/R directionsdeffindPath(root,target,path):ifrootisNone:returnFalseifroot.data==target:returnTrue# Try going leftpath.append('L')iffindPath(root.left,target,path):returnTruepath.pop()# Try going rightpath.append('R')iffindPath(root.right,target,path):returnTruepath.pop()returnFalse# Counts direction changes in a pathdefcountTurns(path):turns=0foriinrange(1,len(path)):ifpath[i]!=path[i-1]:turns+=1returnturns# Returns number of turns required from first node to second nodedefnumberOfTurns(root,p,q):lca=findLCA(root,p,q)iflcaisNone:return-1pathFirst=[]pathSecond=[]# Paths from LCA to both nodesfindPath(lca,p,pathFirst)findPath(lca,q,pathSecond)iflca.data==porlca.data==q:path=pathSecondiflca.data==pelsepathFirstturns=countTurns(path)else:# Add one turn for changing direction at LCAturns=(countTurns(pathFirst)+countTurns(pathSecond)+1)# No turns means straight pathreturn-1ifturns==0elseturnsif__name__=="__main__":# 1# / \# 2 3# / \ / \# 4 5 6 7# / / \# 8 9 10## p = 5# q = 10root=Node(1)root.left=Node(2)root.right=Node(3)root.left.left=Node(4)root.left.right=Node(5)root.right.left=Node(6)root.right.right=Node(7)root.left.left.left=Node(8)root.right.left.left=Node(9)root.right.left.right=Node(10)p=5q=10print(numberOfTurns(root,p,q))
C#
usingSystem;usingSystem.Text;publicclassNode{publicintdata;publicNodeleft;publicNoderight;publicNode(intval){data=val;left=right=null;}}publicclassGFG{// Finds LCA of two given nodespublicstaticNodefindLCA(Noderoot,intp,intq){if(root==null)returnnull;if(root.data==p||root.data==q)returnroot;Nodeleft=findLCA(root.left,p,q);Noderight=findLCA(root.right,p,q);if(left!=null&&right!=null)returnroot;returnleft??right;}// Stores path from root to target node using L/R// directionspublicstaticboolfindPath(Noderoot,inttarget,StringBuilderpath){if(root==null)returnfalse;if(root.data==target)returntrue;// Try going leftpath.Append('L');if(findPath(root.left,target,path))returntrue;path.Length--;// Try going rightpath.Append('R');if(findPath(root.right,target,path))returntrue;path.Length--;returnfalse;}// Counts direction changes in a pathpublicstaticintcountTurns(stringpath){intturns=0;for(inti=1;i<path.Length;i++){if(path[i]!=path[i-1])turns++;}returnturns;}// Returns number of turns required from first node to// second nodepublicstaticintnumberOfTurns(Noderoot,intp,intq){Nodelca=findLCA(root,p,q);if(lca==null)return-1;StringBuilderpathFirst=newStringBuilder();StringBuilderpathSecond=newStringBuilder();// Paths from LCA to both nodesfindPath(lca,p,pathFirst);findPath(lca,q,pathSecond);intturns=0;/* If LCA is one of the nodes, there is no extra turn at LCA because we start from that node. */if(lca.data==p||lca.data==q){stringpath=(lca.data==p)?pathSecond.ToString():pathFirst.ToString();turns=countTurns(path);}else{/* We go: first -> LCA -> second At LCA, we change direction from one subtree to another, so it contributes one turn. */turns=countTurns(pathFirst.ToString())+countTurns(pathSecond.ToString())+1;}// No turns means both nodes lie on a straight pathreturnturns==0?-1:turns;}publicstaticvoidMain(){/* 1 / \ 2 3 / \ / \ 4 5 6 7 / / \ 8 9 10 p = 5 q = 10 */Noderoot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.left=newNode(6);root.right.right=newNode(7);root.left.left.left=newNode(8);root.right.left.left=newNode(9);root.right.left.right=newNode(10);intp=5;intq=10;Console.WriteLine(numberOfTurns(root,p,q));}}
JavaScript
classNode{constructor(val){this.data=val;this.left=null;this.right=null;}}// Finds LCA of two given nodesfunctionfindLCA(root,p,q){if(!root)returnnull;if(root.data===p||root.data===q)returnroot;constleft=findLCA(root.left,p,q);constright=findLCA(root.right,p,q);if(left&&right)returnroot;returnleft||right;}// Stores path from root to target node using L/R directionsfunctionfindPath(root,target,path){if(!root)returnfalse;if(root.data===target)returntrue;// Try going leftpath.push("L");if(findPath(root.left,target,path))returntrue;path.pop();// Try going rightpath.push("R");if(findPath(root.right,target,path))returntrue;path.pop();returnfalse;}// Counts direction changes in a pathfunctioncountTurns(path){letturns=0;for(leti=1;i<path.length;i++){if(path[i]!==path[i-1])turns++;}returnturns;}// Returns number of turns required from first node to// second nodefunctionnumberOfTurns(root,p,q){constlca=findLCA(root,p,q);if(!lca)return-1;constpathFirst=[];constpathSecond=[];// Paths from LCA to both nodesfindPath(lca,p,pathFirst);findPath(lca,q,pathSecond);letturns=0;/* If LCA is one of the nodes, there is no extra turn at LCA because we start from that node. */if(lca.data===p||lca.data===q){constpath=(lca.data===p)?pathSecond:pathFirst;turns=countTurns(path);}else{/* We go: first -> LCA -> second At LCA, we change direction from one subtree to another, so it contributes one turn. */turns=countTurns(pathFirst)+countTurns(pathSecond)+1;}// No turns means both nodes lie on a straight pathreturnturns===0?-1:turns;}// Driver Code/* 1 / \ 2 3 / \ / \ 4 5 6 7 / / \ 8 9 10 p = 5 q = 10*/constroot=newNode(1);root.left=newNode(2);root.right=newNode(3);root.left.left=newNode(4);root.left.right=newNode(5);root.right.left=newNode(6);root.right.right=newNode(7);root.left.left.left=newNode(8);root.right.left.left=newNode(9);root.right.left.right=newNode(10);constp=5;constq=10;console.log(numberOfTurns(root,p,q));