Given root of a binary tree in which all node values are distinct, count pairs of nodes that violate any of the following Binary Search Tree (BST) properties.
All values in the left subtree are strictly smaller.
All values in the right subtree are strictly greater.
Examples:
Input: root[] = [10, 50, 40, N, N, 20, 30] Output: 5 Explanation: Pairs violating BST property are: (10, 50), 10 should be greater than its left child value. (40, 30), 40 should be less than its right child value. (50, 20), (50, 30) and (50, 40), maximum of left subtree of 10 is 50 greater than 20, 30 and 40 of its right subtree.
Input: root[] = [80, 40, 30, 70, N, 60, 50]
Output: 10 Explanation: There are total 10 pairs (80, 30), (80, 60), (80, 50), (30, 60), (40, 70), (40, 30), (40, 50), (70, 30), (70, 60), (70, 50) which violate the BST properties.
[Naive Approach] Check All Pairs in Inorder Traversal - O(n^2) Time and O(n) Space
The idea is to first perform an inorder traversal and store the node values in an array.
In a valid BST, this array should be sorted in strictly increasing order. Therefore, every pair (i, j) where i < j and arr[i] > arr[j] represents a pair that violates the BST property.
Working of the Approach:
Perform inorder traversal of the binary tree and store all node values.
Initialize the count of violating pairs as 0.
Consider every pair of indices (i, j) where i < j.
If arr[i] > arr[j], increment the count.
Return the total count.
C++
#include<bits/stdc++.h>usingnamespacestd;structNode{intdata;Node*left;Node*right;Node(intval){data=val;left=right=nullptr;}};voidinorder(Node*root,vector<int>&arr){if(root==nullptr)return;inorder(root->left,arr);arr.push_back(root->data);inorder(root->right,arr);}intpairsViolatingBST(Node*root){vector<int>arr;inorder(root,arr);intcount=0;// Count inversion pairs in inorder traversal.for(inti=0;i<arr.size();i++){for(intj=i+1;j<arr.size();j++){if(arr[i]>arr[j])count++;}}returncount;}intmain(){Node*root=newNode(10);root->left=newNode(50);root->right=newNode(40);root->right->left=newNode(20);root->right->right=newNode(30);cout<<pairsViolatingBST(root)<<endl;return0;}
Java
importjava.util.ArrayList;classNode{intdata;Nodeleft,right;Node(intval){data=val;left=right=null;}}classGFG{staticvoidinorder(Noderoot,ArrayList<Integer>arr){if(root==null)return;inorder(root.left,arr);arr.add(root.data);inorder(root.right,arr);}staticintpairsViolatingBST(Noderoot){ArrayList<Integer>arr=newArrayList<>();inorder(root,arr);intcount=0;// Count inversion pairs in inorder traversal.for(inti=0;i<arr.size();i++){for(intj=i+1;j<arr.size();j++){if(arr.get(i)>arr.get(j))count++;}}returncount;}publicstaticvoidmain(String[]args){Noderoot=newNode(10);root.left=newNode(50);root.right=newNode(40);root.right.left=newNode(20);root.right.right=newNode(30);System.out.println(pairsViolatingBST(root));}}
Python
classNode:def__init__(self,val):self.data=valself.left=Noneself.right=Nonedefinorder(root,arr):ifrootisNone:returninorder(root.left,arr)arr.append(root.data)inorder(root.right,arr)defpairsViolatingBST(root):arr=[]inorder(root,arr)count=0# Count inversion pairs in inorder traversal.foriinrange(len(arr)):forjinrange(i+1,len(arr)):ifarr[i]>arr[j]:count+=1returncountif__name__=="__main__":root=Node(10)root.left=Node(50)root.right=Node(40)root.right.left=Node(20)root.right.right=Node(30)print(pairsViolatingBST(root))
C#
usingSystem;usingSystem.Collections.Generic;classNode{publicintdata;publicNodeleft;publicNoderight;publicNode(intval){data=val;left=right=null;}}classGFG{staticvoidinorder(Noderoot,List<int>arr){if(root==null)return;inorder(root.left,arr);arr.Add(root.data);inorder(root.right,arr);}staticintpairsViolatingBST(Noderoot){List<int>arr=newList<int>();inorder(root,arr);intcount=0;// Count inversion pairs in inorder traversal.for(inti=0;i<arr.Count;i++){for(intj=i+1;j<arr.Count;j++){if(arr[i]>arr[j])count++;}}returncount;}staticvoidMain(){Noderoot=newNode(10);root.left=newNode(50);root.right=newNode(40);root.right.left=newNode(20);root.right.right=newNode(30);Console.WriteLine(pairsViolatingBST(root));}}
JavaScript
classNode{constructor(data){this.data=data;this.left=null;this.right=null;}}functioninorder(root,arr){if(root===null)return;inorder(root.left,arr);arr.push(root.data);inorder(root.right,arr);}functionpairsViolatingBST(root){letarr=[];inorder(root,arr);letcount=0;// Count inversion pairs in inorder traversal.for(leti=0;i<arr.length;i++){for(letj=i+1;j<arr.length;j++){if(arr[i]>arr[j])count++;}}returncount;}// Driver Codeconstroot=newNode(10);root.left=newNode(50);root.right=newNode(40);root.right.left=newNode(20);root.right.right=newNode(30);console.log(pairsViolatingBST(root));
Output
5
[Expected Approach] Count Inversions Using Merge Sort - O(n log n) Time and O(n) Space
The idea is to observe that the inorder traversal of a valid BST must be strictly increasing.
Therefore, every pair of values in the inorder traversal where an earlier value is greater than a later value represents a pair violating the BST property.
Instead of checking all pairs in O(n2), we count these inversions efficiently using Merge Sort in O(n log n) time.
Working of the Approach:
Perform an inorder traversal of the binary tree and store all node values in an array.
Apply Merge Sort on this array while counting inversions.
During the merge step, if an element from the right half is smaller than an element from the left half, all remaining elements in the left half also form violating pairs with it.
Add the number of such remaining elements to the count.
Continue merging until the entire array is processed.
Return the total inversion count as the number of pairs violating the BST property.
C++
#include<bits/stdc++.h>usingnamespacestd;structNode{intdata;Node*left;Node*right;Node(intval){data=val;left=right=nullptr;}};voidinorder(Node*root,vector<int>&arr){if(root==nullptr)return;inorder(root->left,arr);arr.push_back(root->data);inorder(root->right,arr);}longlongmergeSort(vector<int>&arr,intlow,inthigh){if(low>=high)return0;intmid=low+(high-low)/2;longlongcount=mergeSort(arr,low,mid);count+=mergeSort(arr,mid+1,high);vector<int>temp;inti=low,j=mid+1;while(i<=mid&&j<=high){if(arr[i]<=arr[j]){temp.push_back(arr[i++]);}else{// Count inversions with remaining left elements.count+=mid-i+1;temp.push_back(arr[j++]);}}while(i<=mid)temp.push_back(arr[i++]);while(j<=high)temp.push_back(arr[j++]);for(intk=0;k<temp.size();k++)arr[low+k]=temp[k];returncount;}intpairsViolatingBST(Node*root){vector<int>arr;inorder(root,arr);return(int)mergeSort(arr,0,arr.size()-1);}intmain(){Node*root=newNode(10);root->left=newNode(50);root->right=newNode(40);root->right->left=newNode(20);root->right->right=newNode(30);cout<<pairsViolatingBST(root)<<endl;return0;}
Java
importjava.util.*;classNode{intdata;Nodeleft,right;Node(intval){data=val;left=right=null;}}classGFG{staticvoidinorder(Noderoot,ArrayList<Integer>arr){if(root==null)return;inorder(root.left,arr);arr.add(root.data);inorder(root.right,arr);}staticvoidmerge(int[]arr,intlow,intmid,inthigh,long[]count){int[]temp=newint[high-low+1];inti=low,j=mid+1,k=0;while(i<=mid&&j<=high){if(arr[i]<=arr[j]){temp[k++]=arr[i++];}else{// Count inversions formed with the remaining left elements.count[0]+=mid-i+1;temp[k++]=arr[j++];}}while(i<=mid)temp[k++]=arr[i++];while(j<=high)temp[k++]=arr[j++];for(i=low,k=0;i<=high;i++,k++)arr[i]=temp[k];}staticvoidmergeSort(int[]arr,intlow,inthigh,long[]count){if(low>=high)return;intmid=low+(high-low)/2;mergeSort(arr,low,mid,count);mergeSort(arr,mid+1,high,count);merge(arr,low,mid,high,count);}staticintpairsViolatingBST(Noderoot){ArrayList<Integer>list=newArrayList<>();inorder(root,list);int[]arr=newint[list.size()];for(inti=0;i<list.size();i++)arr[i]=list.get(i);long[]count={0};mergeSort(arr,0,arr.length-1,count);return(int)count[0];}publicstaticvoidmain(String[]args){Noderoot=newNode(10);root.left=newNode(50);root.right=newNode(40);root.right.left=newNode(20);root.right.right=newNode(30);System.out.println(pairsViolatingBST(root));}}
Python
classNode:def__init__(self,val):self.data=valself.left=Noneself.right=Nonedefinorder(root,arr):ifrootisNone:returninorder(root.left,arr)arr.append(root.data)inorder(root.right,arr)defmergeSort(arr):iflen(arr)<=1:returnarr,0mid=len(arr)//2left,countLeft=mergeSort(arr[:mid])right,countRight=mergeSort(arr[mid:])merged=[]i=j=0count=countLeft+countRightwhilei<len(left)andj<len(right):ifleft[i]<=right[j]:merged.append(left[i])i+=1else:# Count inversions formed with the remaining left elements.count+=len(left)-imerged.append(right[j])j+=1merged.extend(left[i:])merged.extend(right[j:])returnmerged,countdefpairsViolatingBST(root):arr=[]inorder(root,arr)_,count=mergeSort(arr)returncountif__name__=="__main__":root=Node(10)root.left=Node(50)root.right=Node(40)root.right.left=Node(20)root.right.right=Node(30)print(pairsViolatingBST(root))
C#
usingSystem;usingSystem.Collections.Generic;classNode{publicintdata;publicNodeleft;publicNoderight;publicNode(intval){data=val;left=right=null;}}classGFG{staticvoidinorder(Noderoot,List<int>arr){if(root==null)return;inorder(root.left,arr);arr.Add(root.data);inorder(root.right,arr);}staticvoidmerge(int[]arr,intlow,intmid,inthigh,reflongcount){int[]temp=newint[high-low+1];inti=low,j=mid+1,k=0;while(i<=mid&&j<=high){if(arr[i]<=arr[j]){temp[k++]=arr[i++];}else{// Count inversions formed with the remaining left elements.count+=mid-i+1;temp[k++]=arr[j++];}}while(i<=mid)temp[k++]=arr[i++];while(j<=high)temp[k++]=arr[j++];for(i=low,k=0;i<=high;i++,k++)arr[i]=temp[k];}staticvoidmergeSort(int[]arr,intlow,inthigh,reflongcount){if(low>=high)return;intmid=low+(high-low)/2;mergeSort(arr,low,mid,refcount);mergeSort(arr,mid+1,high,refcount);merge(arr,low,mid,high,refcount);}staticintpairsViolatingBST(Noderoot){List<int>list=newList<int>();inorder(root,list);int[]arr=list.ToArray();longcount=0;mergeSort(arr,0,arr.Length-1,refcount);return(int)count;}staticvoidMain(){Noderoot=newNode(10);root.left=newNode(50);root.right=newNode(40);root.right.left=newNode(20);root.right.right=newNode(30);Console.WriteLine(pairsViolatingBST(root));}}
JavaScript
classNode{constructor(data){this.data=data;this.left=null;this.right=null;}}functioninorder(root,arr){if(root===null)return;inorder(root.left,arr);arr.push(root.data);inorder(root.right,arr);}functionmergeSort(arr){if(arr.length<=1)return[arr,0];letmid=Math.floor(arr.length/2);let[left,countLeft]=mergeSort(arr.slice(0,mid));let[right,countRight]=mergeSort(arr.slice(mid));letmerged=[];leti=0,j=0;letcount=countLeft+countRight;while(i<left.length&&j<right.length){if(left[i]<=right[j]){merged.push(left[i++]);}else{// Count inversions formed with the remaining left elements.count+=left.length-i;merged.push(right[j++]);}}while(i<left.length)merged.push(left[i++]);while(j<right.length)merged.push(right[j++]);return[merged,count];}functionpairsViolatingBST(root){letarr=[];inorder(root,arr);let[sorted,count]=mergeSort(arr);returncount;}// Driver Codeconstroot=newNode(10);root.left=newNode(50);root.right=newNode(40);root.right.left=newNode(20);root.right.right=newNode(30);console.log(pairsViolatingBST(root));