Given a Binary search Tree that contains positive integer values greater than 0. The task is to check whether the BST contains a dead end or not.
A node becomes a dead end when both of its adjacent values that is, (value - 1) and (value + 1) — are already present in the tree. In such cases, no new node can be inserted in that position.
Examples:
Input: root[] = [8, 5, 9, 2, 7, N, N, 1]
Output: true
Explanation: Node 1 is a Dead End in the given BST. We can neither insert 0 as only positives are allowed not insert 3 (because 3 cannot be inserted as left of 2)Input: root[] = [8, 7, 10, 2, N, 9, 13]
Output: true
Explanation: Node 9 is a Dead End in the given BST.
Table of Content
[Naive Approach] Recursion - O(n * h) time and O(h) space
The idea is to iterate through each leaf node and check whether the values
value - 1andvalue + 1exist in the tree.If both previous and next values are present, it indicates a dead end, and the function returns
true.
// C++ program to Check whether BST contains Dead End or not
#include <bits/stdc++.h>
using namespace std;
class Node {
public:
int data;
Node *left, *right;
Node(int val){
data = val;
left = nullptr;
right = nullptr;
}
};
bool findVal(Node* root, int val) {
// For non-positive values, return true
// (as these values cannot be inserted)
if (val <= 0) return true;
if (root == nullptr) return false;
if (root->data == val) return true;
else if (root->data < val) return findVal(root->right, val);
return findVal(root->left, val);
}
bool dfs(Node* curr, Node* root) {
// Base Case
if (curr == nullptr) return false;
// If value val - 1 and val + 1 already
// exists in the tree, and this node is
// a leaf node, return true.
if (curr->left == nullptr && curr->right == nullptr) {
int val = curr->data;
return findVal(root, val-1) && findVal(root, val+1);
}
return dfs(curr->left, root) || dfs(curr->right, root);
}
bool isDeadEnd(Node *root) {
return dfs(root, root);
}
int main() {
Node* root = new Node(8);
root->left = new Node(5);
root->right = new Node(9);
root->left->left = new Node(2);
root->left->right = new Node(7);
root->left->left->left = new Node(1);
if (isDeadEnd(root)) {
cout << "true" << endl;
} else {
cout << "false" << endl;
}
return 0;
}
// Java program to Check whether BST contains Dead End or not
class Node {
int data;
Node left, right;
Node(int val) {
data = val;
left = null;
right = null;
}
}
class GfG {
static boolean findVal(Node root, int val) {
// For non-positive values, return true
// (as these values cannot be inserted)
if (val <= 0) return true;
if (root == null) return false;
if (root.data == val) return true;
else if (root.data < val) return findVal(root.right, val);
return findVal(root.left, val);
}
static boolean dfs(Node curr, Node root) {
// Base Case
if (curr == null) return false;
// If value val - 1 and val + 1 already
// exists in the tree, and this node is
// a leaf node, return true.
if (curr.left == null && curr.right == null) {
int val = curr.data;
return findVal(root, val-1) && findVal(root, val+1);
}
return dfs(curr.left, root) || dfs(curr.right, root);
}
static boolean isDeadEnd(Node root) {
return dfs(root, root);
}
public static void main(String[] args) {
Node root = new Node(8);
root.left = new Node(5);
root.right = new Node(9);
root.left.left = new Node(2);
root.left.right = new Node(7);
root.left.left.left = new Node(1);
System.out.println(isDeadEnd(root));
}
}
# Python program to Check whether BST contains Dead End or not
class Node:
def __init__(self, val):
self.data = val
self.left = None
self.right = None
def findVal(root, val):
# For non-positive values, return true
# (as these values cannot be inserted)
if val <= 0:
return True
if root is None:
return False
if root.data == val:
return True
elif root.data < val:
return findVal(root.right, val)
return findVal(root.left, val)
def dfs(curr, root):
# Base Case
if curr is None:
return False
# If value val - 1 and val + 1 already
# exists in the tree, and this node is
# a leaf node, return true.
if curr.left is None and curr.right is None:
val = curr.data
return findVal(root, val-1) and findVal(root, val+1)
return dfs(curr.left, root) or dfs(curr.right, root)
def isDeadEnd(root):
return dfs(root, root)
if __name__ == "__main__":
root = Node(8)
root.left = Node(5)
root.right = Node(9)
root.left.left = Node(2)
root.left.right = Node(7)
root.left.left.left = Node(1)
if isDeadEnd(root):
print("true")
else:
print("false")
using System;
class Node {
public int data;
public Node left, right;
public Node(int val) {
data = val;
left = null;
right = null;
}
}
class Solution {
static bool FindVal(Node root, int val) {
// Non-positive values cannot be inserted
if (val <= 0) return true;
if (root == null) return false;
if (root.data == val) return true;
if (root.data < val)
return FindVal(root.right, val);
return FindVal(root.left, val);
}
static bool Dfs(Node curr, Node root) {
if (curr == null) return false;
// Check whether a leaf node is a dead end
if (curr.left == null && curr.right == null) {
int val = curr.data;
return FindVal(root, val - 1) &&
FindVal(root, val + 1);
}
return Dfs(curr.left, root) ||
Dfs(curr.right, root);
}
public bool isDeadEnd(Node root) {
return Dfs(root, root);
}
public static void Main() {
Node root = new Node(8);
root.left = new Node(5);
root.right = new Node(9);
root.left.left = new Node(2);
root.left.right = new Node(7);
root.left.left.left = new Node(1);
Solution obj = new Solution();
bool result = obj.isDeadEnd(root);
Console.WriteLine(result ? "true" : "false");
}
}
// JavaScript program to Check whether BST contains Dead End or not
class Node {
constructor(val) {
this.data = val;
this.left = null;
this.right = null;
}
}
function findVal(root, val) {
// For non-positive values, return true
// (as these values cannot be inserted)
if (val <= 0) return true;
if (root === null) return false;
if (root.data === val) return true;
else if (root.data < val) return findVal(root.right, val);
return findVal(root.left, val);
}
function dfs(curr, root) {
// Base Case
if (curr === null) return false;
// If value val - 1 and val + 1 already
// exists in the tree, and this node is
// a leaf node, return true.
if (curr.left === null && curr.right === null) {
let val = curr.data;
return findVal(root, val-1) && findVal(root, val+1);
}
return dfs(curr.left, root) || dfs(curr.right, root);
}
function isDeadEnd(root) {
return dfs(root, root);
}
// Driver Code
let root = new Node(8);
root.left = new Node(5);
root.right = new Node(9);
root.left.left = new Node(2);
root.left.right = new Node(7);
root.left.left.left = new Node(1);
if (isDeadEnd(root)) {
console.log("true");
} else {
console.log("false");
}
Output
true
[Better Approach] Hash Set - O(n) time and O(n) space
The idea is to store all node values in a set.
Traverse the tree again and for each leaf node, check if both (value - 1) and (value + 1) exist in the same set. If yes, it indicates a dead end.
- Traverse the BST and insert each node value into a set for all nodes.
- Traverse again, and for every leaf value check, check if both (value - 1) and (value + 1) exist in the set.
- If such a condition is found for any leaf node, return true. Else, return false.
// C++ program to Check whether BST contains Dead End or not
#include <bits/stdc++.h>
using namespace std;
class Node {
public:
int data;
Node *left, *right;
Node(int val){
data = val;
left = nullptr;
right = nullptr;
}
};
// Recursive function to insert all nodes
// into a hash set.
void storeAllNodes(Node* root, unordered_set<int>& nodeSet) {
if (!root) return;
nodeSet.insert(root->data);
storeAllNodes(root->left, nodeSet);
storeAllNodes(root->right, nodeSet);
}
// Recursive function to check if a leaf node
// is dead end or not.
bool deadEndRecur(Node* root, unordered_set<int>& nodeSet) {
if (!root) return false;
// Check leaf node is dead end or not.
if (!root->left && !root->right) {
int val = root->data;
if (nodeSet.count(val - 1) && nodeSet.count(val + 1))
return true;
}
return deadEndRecur(root->left, nodeSet) ||
deadEndRecur(root->right, nodeSet);
}
bool isDeadEnd(Node *root) {
unordered_set<int> nodeSet;
// to handle case when node value is 1
nodeSet.insert(0);
storeAllNodes(root, nodeSet);
return deadEndRecur(root, nodeSet);
}
int main() {
Node* root = new Node(8);
root->left = new Node(5);
root->right = new Node(9);
root->left->left = new Node(2);
root->left->right = new Node(7);
root->left->left->left = new Node(1);
if (isDeadEnd(root)) {
cout << "true" << endl;
} else {
cout << "false" << endl;
}
return 0;
}
// Java program to Check whether BST contains Dead End or not
import java.util.HashSet;
import java.util.Set;
class Node {
int data;
Node left, right;
Node(int val) {
data = val;
left = null;
right = null;
}
}
class GfG {
// Recursive function to insert all nodes
// into a hash set.
static void storeAllNodes(Node root, Set<Integer> nodeSet) {
if (root == null) return;
nodeSet.add(root.data);
storeAllNodes(root.left, nodeSet);
storeAllNodes(root.right, nodeSet);
}
// Recursive function to check if a leaf node
// is dead end or not.
static boolean deadEndRecur(Node root, Set<Integer> nodeSet) {
if (root == null) return false;
// Check leaf node is dead end or not.
if (root.left == null && root.right == null) {
int val = root.data;
if (nodeSet.contains(val - 1) && nodeSet.contains(val + 1))
return true;
}
return deadEndRecur(root.left, nodeSet) ||
deadEndRecur(root.right, nodeSet);
}
static boolean isDeadEnd(Node root) {
Set<Integer> nodeSet = new HashSet<>();
// to handle case when node value is 1
nodeSet.add(0);
storeAllNodes(root, nodeSet);
return deadEndRecur(root, nodeSet);
}
public static void main(String[] args) {
Node root = new Node(8);
root.left = new Node(5);
root.right = new Node(9);
root.left.left = new Node(2);
root.left.right = new Node(7);
root.left.left.left = new Node(1);
System.out.println(isDeadEnd(root));
}
}
# Python program to Check whether BST contains Dead End or not
class Node:
def __init__(self, val):
self.data = val
self.left = None
self.right = None
# Recursive function to insert all nodes
# into a hash set.
def storeAllNodes(root, nodeSet):
if not root:
return
nodeSet.add(root.data)
storeAllNodes(root.left, nodeSet)
storeAllNodes(root.right, nodeSet)
# Recursive function to check if a leaf node
# is dead end or not.
def deadEndRecur(root, nodeSet):
if not root:
return False
# Check leaf node is dead end or not.
if not root.left and not root.right:
val = root.data
if (val - 1 in nodeSet) and (val + 1 in nodeSet):
return True
return deadEndRecur(root.left, nodeSet) or \
deadEndRecur(root.right, nodeSet)
def isDeadEnd(root):
nodeSet = set()
# to handle case when node value is 1
nodeSet.add(0)
storeAllNodes(root, nodeSet)
return deadEndRecur(root, nodeSet)
if __name__ == "__main__":
root = Node(8)
root.left = Node(5)
root.right = Node(9)
root.left.left = Node(2)
root.left.right = Node(7)
root.left.left.left = Node(1)
if isDeadEnd(root):
print("true")
else:
print("false")
// C# program to Check whether BST contains Dead End or not
using System;
using System.Collections.Generic;
class Node {
public int data;
public Node left, right;
public Node(int val) {
data = val;
left = null;
right = null;
}
}
class GfG {
// Recursive function to insert all nodes
// into a hash set.
static void storeAllNodes(Node root, HashSet<int> nodeSet) {
if (root == null) return;
nodeSet.Add(root.data);
storeAllNodes(root.left, nodeSet);
storeAllNodes(root.right, nodeSet);
}
// Recursive function to check if a leaf node
// is dead end or not.
static bool deadEndRecur(Node root, HashSet<int> nodeSet) {
if (root == null) return false;
// Check leaf node is dead end or not.
if (root.left == null && root.right == null) {
int val = root.data;
if (nodeSet.Contains(val - 1) && nodeSet.Contains(val + 1))
return true;
}
return deadEndRecur(root.left, nodeSet) ||
deadEndRecur(root.right, nodeSet);
}
static bool isDeadEnd(Node root) {
HashSet<int> nodeSet = new HashSet<int>();
// to handle case when node value is 1
nodeSet.Add(0);
storeAllNodes(root, nodeSet);
return deadEndRecur(root, nodeSet);
}
static void Main() {
Node root = new Node(8);
root.left = new Node(5);
root.right = new Node(9);
root.left.left = new Node(2);
root.left.right = new Node(7);
root.left.left.left = new Node(1);
if (isDeadEnd(root)) {
Console.WriteLine("true");
} else {
Console.WriteLine("false");
}
}
}
// JavaScript program to Check whether BST contains Dead End or not
class Node {
constructor(val) {
this.data = val;
this.left = null;
this.right = null;
}
}
// Recursive function to insert all nodes
// into a hash set.
function storeAllNodes(root, nodeSet) {
if (!root) return;
nodeSet.add(root.data);
storeAllNodes(root.left, nodeSet);
storeAllNodes(root.right, nodeSet);
}
// Recursive function to check if a leaf node
// is dead end or not.
function deadEndRecur(root, nodeSet) {
if (!root) return false;
// Check leaf node is dead end or not.
if (!root.left && !root.right) {
const val = root.data;
if (nodeSet.has(val - 1) && nodeSet.has(val + 1))
return true;
}
return deadEndRecur(root.left, nodeSet) ||
deadEndRecur(root.right, nodeSet);
}
function isDeadEnd(root) {
const nodeSet = new Set();
// to handle case when node value is 1
nodeSet.add(0);
storeAllNodes(root, nodeSet);
return deadEndRecur(root, nodeSet);
}
// Driver Code
const root = new Node(8);
root.left = new Node(5);
root.right = new Node(9);
root.left.left = new Node(2);
root.left.right = new Node(7);
root.left.left.left = new Node(1);
console.log(isDeadEnd(root));
Output
true
[Optimized Approach] Recursion and Range Values - O(n) time and O(h) space
The idea is to perform depth first search traversal on the tree, while maintaining the range of each subtree root.
If for any leaf node, the size of range becomes 1 (this value is taken by leaf node already), it means no node can be inserted to this leaf node, and hence it is a dead end.
Step by step approach:
- Perform Depth first search on the root node and initialize the range as [1, Integer Maximum].
- For each node, If node is null, return false. If node is leaf node and the range of node is 1, return true as no other node can be inserted.
- Recur for left and right subtree.
// C++ program to Check whether BST contains Dead End or not
#include <bits/stdc++.h>
using namespace std;
class Node {
public:
int data;
Node *left, *right;
Node(int val){
data = val;
left = nullptr;
right = nullptr;
}
};
// Here mini and maxi defines the range of
// the subtree root. If the range consists
// only of 1 value (root value), it means
// no other value cannot be added to this.
bool dfs(Node* root, int mini, int maxi) {
// Base Case
if (root == nullptr) return false;
// If leaf node and no range left
if (root->left == nullptr && root->right == nullptr &&
mini == maxi) {
return true;
}
return dfs(root->left, mini, root->data-1) ||
dfs(root->right, root->data+1, maxi);
}
bool isDeadEnd(Node *root) {
return dfs(root, 1, INT_MAX);
}
int main() {
Node* root = new Node(8);
root->left = new Node(5);
root->right = new Node(9);
root->left->left = new Node(2);
root->left->right = new Node(7);
root->left->left->left = new Node(1);
if (isDeadEnd(root)) {
cout << "true" << endl;
} else {
cout << "false" << endl;
}
return 0;
}
// Java program to Check whether BST contains Dead End or not
class Node {
int data;
Node left, right;
Node(int val) {
data = val;
left = null;
right = null;
}
}
class GfG {
// Here mini and maxi defines the range of
// the subtree root. If the range consists
// only of 1 value (root value), it means
// no other value cannot be added to this.
static boolean dfs(Node root, int mini, int maxi) {
// Base Case
if (root == null) return false;
// If leaf node and no range left
if (root.left == null && root.right == null &&
mini == maxi) {
return true;
}
return dfs(root.left, mini, root.data-1) ||
dfs(root.right, root.data+1, maxi);
}
static boolean isDeadEnd(Node root) {
return dfs(root, 1, Integer.MAX_VALUE);
}
public static void main(String[] args) {
Node root = new Node(8);
root.left = new Node(5);
root.right = new Node(9);
root.left.left = new Node(2);
root.left.right = new Node(7);
root.left.left.left = new Node(1);
System.out.println(isDeadEnd(root));
}
}
# Python program to Check whether BST contains Dead End or not
class Node:
def __init__(self, val):
self.data = val
self.left = None
self.right = None
# Here mini and maxi defines the range of
# the subtree root. If the range consists
# only of 1 value (root value), it means
# no other value cannot be added to this.
def dfs(root, mini, maxi):
# Base Case
if root is None:
return False
# If leaf node and no range left
if root.left is None and root.right is None and mini == maxi:
return True
return dfs(root.left, mini, root.data-1) or dfs(root.right, root.data+1, maxi)
def isDeadEnd(root):
return dfs(root, 1, float('inf'))
if __name__ == "__main__":
root = Node(8)
root.left = Node(5)
root.right = Node(9)
root.left.left = Node(2)
root.left.right = Node(7)
root.left.left.left = Node(1)
if isDeadEnd(root):
print("true")
else:
print("false")
using System;
class Node {
public int data;
public Node left, right;
public Node(int val) {
data = val;
left = null;
right = null;
}
}
class Solution {
// mini and maxi define the valid range
static bool Dfs(Node root, int mini, int maxi) {
// Base Case
if (root == null) return false;
// Leaf node with no value left
if (root.left == null && root.right == null &&
mini == maxi) {
return true;
}
return Dfs(root.left, mini, root.data - 1) ||
Dfs(root.right, root.data + 1, maxi);
}
public bool isDeadEnd(Node root) {
return Dfs(root, 1, int.MaxValue);
}
public static void Main() {
Node root = new Node(8);
root.left = new Node(5);
root.right = new Node(9);
root.left.left = new Node(2);
root.left.right = new Node(7);
root.left.left.left = new Node(1);
Solution obj = new Solution();
bool result = obj.isDeadEnd(root);
Console.WriteLine(result ? "true" : "false");
}
}
// JavaScript program to Check whether BST contains Dead End or not
class Node {
constructor(val) {
this.data = val;
this.left = null;
this.right = null;
}
}
// Here mini and maxi defines the range of
// the subtree root. If the range consists
// only of 1 value (root value), it means
// no other value cannot be added to this.
function dfs(root, mini, maxi) {
// Base Case
if (root === null) return false;
// If leaf node and no range left
if (root.left === null && root.right === null &&
mini === maxi) {
return true;
}
return dfs(root.left, mini, root.data-1) ||
dfs(root.right, root.data+1, maxi);
}
function isDeadEnd(root) {
return dfs(root, 1, Number.MAX_SAFE_INTEGER);
}
// Driver Code
let root = new Node(8);
root.left = new Node(5);
root.right = new Node(9);
root.left.left = new Node(2);
root.left.right = new Node(7);
root.left.left.left = new Node(1);
console.log(isDeadEnd(root));
Output
true
Output:
Output: