Runway reservation system

Runway reservation system

Given an airport with a single runway, we have to design a runway reservation system of that airport. Add to details: each reservation request comes with requested landing time let’s say t. Landing can go through if there is no landing scheduled within k minutes of requested time, that means t can be added to the set of scheduling landings. K can vary and depends on external conditions. This system helps with reservations for the future landings.
Once the plane lands safely, we have to remove the plane for landing sets.

This is perfectly possible with airports with multiple runways where only one runway can be used because of weather conditions, maintenance etc. Also, one landing cannot follow another immediately due safety reasons, that’s why there has to be some minimum time before another landing takes place. We have to build this system with given constraints.

In nutshell, we have create a set of landings which are compatible with each other, i.e they do not violate the constraint put.  There are two operations to be performed on this set : insertion and removal. Insertion involves checking of constraints. 

Example: let’s say below is the timeline of all the landing currently scheduled and k = 3 min

reservation system

Now, if the new request comes for landing at 48.5, it should be added to the set as it does not violate the constraint of k mins. However, if a request comes for landing at 53, it cannot be added as it violates the constraint.
If a new request comes for 35, it is invalid as the request is in past.

Reservation system: thoughts

What is the most brute force solution which comes to mind? We can store all the incoming requests in an unsorted array.  Insertion should be O(1) operation as it is at the end. However, checking the constrain that it is satisfied will take O(n) because we have to scan through the entire array.
Same is true even if we use unsorted linked list. 

How about a sorted array? We can use a binary search algorithm to find the constraint, which will take O(log n) complexity. However, the insertion will still be O(n) as we have to move all the elements to the right from the position of insertion.

Sorted list solves the problem of insertion in O(1) but then search for the constraint will be O(n) complexity. It just moves the problem from one place to another.

Reservation system using binary search tree

We have to optimize two things : first check if the new request meets the constraints, second insert the new request into the set. 

Let’s think of binary search tree. To check a constraint, we have to check each node of the binary tree, but based on the relationship of the current node and the new request time, we can discard half of the tree. (Binary search tree property, where all the nodes on the left side are smaller than the root node and all the nodes on the right side are greater than the current node)

When a new request comes, we check with the root node and it does not violate the constraints, then we check if the requested time is less than the root. If yes, we go to left subtree and check there. If requested landing time is greater than the root node, we go to right subtree.
When we reach the leaf node, we add a new node with new landing time as the value of that node.

If at any given node, the constraint is violated, i.e not new landing time is within k minutes of time in the node, then we just return stating it is not possible to add new landing.

What will be complexity of checking the constraint? It will be O(h) where h is height of binary search tree. Insert is then O(1) operation.

Reservation system implementation

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
 
struct node{
    int value;
    struct node *left;
    struct node *right;
};
typedef struct node Node;

void inoderTraversal(Node * root){
    if(!root) return;
	
    inoderTraversal(root->left);
    printf("%d ", root->value);
    inoderTraversal(root->right);
}

Node *createNode(int value){
    Node * newNode =  (Node *)malloc(sizeof(Node));
    
    newNode->value = value;
    newNode->right= NULL;
    newNode->left = NULL;
	
    return newNode;
}

Node *addNode(Node *node, int value, int K){
	if(!node)
        return createNode(value);
    
    if ( node->value + K > value && node->value - K < value ){
        return node;
    }
    if (node->value > value)
        node->left = addNode(node->left, value, K);
    else
        node->right = addNode(node->right, value, K);
    return node;
}

/* Driver program for the function written above */
int main(){
    Node *root = NULL;
	
    //Creating a binary tree
    root = addNode(root, 30, 3);
    root = addNode(root, 20, 3);
    root = addNode(root, 15, 3);
    root = addNode(root, 25, 3);
    root = addNode(root, 40, 3);
    root = addNode(root, 38, 3);
    root = addNode(root, 45, 3);
    inoderTraversal(root);
	
    return 0;
}

Let’s say a new requirement comes which is to find how many flights are scheduled till time t?

This problem can easily be solved using binary search tree, by keeping track of size of subtree at each node as shown in figure below.

runway reservation system

While inserting a new node, update counter of all the nodes on the nodes. When query is run, just return the count of node of that time or closest and smaller than that value of t. 

Please share if there is something wrong or missing. If you are preparing for an interview, please signup to receive free preparation material.

Closest element in binary search tree

Closest element in a binary search tree

The problem statement is: given a binary search tree and a value, find the closest element to that value in the binary search tree. For example, if below is the binary search tree and value given is 16, then the function should return 15.

closest element in binary search tree
Closest element in a binary search tree

Closest element in BST: thoughts

A simple approach is to go to all nodes of BST and find out the difference between the given value and value of the node. Get the minimum absolute value and add that minimum value from the given value, we would get the closest element in the BST.

Do we really need to scan all the nodes? No we don’t need to. Let’s say given value is k.

What if current.value is equal to the k? That means it is the closest node to the k and we cannot go better than this. Return the node value as closest value.

If current.value is greater than k, by virtue of BST, we know that nodes on the right subtree of the current node would be greater than the current.value. Hence the difference between k and all the nodes on the right subtree would only increase. So, there is no node on the right side, which is closer than the current node itself. Hence, the right subtree is discarded. If there is no left subtree, return current.value.

If current.value is less than k,  with the same logic above, all elements in left subtree are less than the value of current.value, the difference between k and the nodes on left subtree would only increase. So, we can safely discard the left subtree. If there is no right subtree, return current.value.

When we return the closest element from left subtree, we check if the difference between current.value and k less than difference between returned value and k. If it is less, then return current.value else return the returned value from the subtree.

Closest element in a binary search tree: algorithm

  1. If k == current.value, return current.value.
  2. If k < current.value, search the closest element in left subtree including the root as current is still a candidate.
    1. Return current.value if there is no left subtree.
  3. If k > current.value, search the closest element in the right subtree.
    1. Return current.value if there is no right subtree.
  4. If abs(current.value - k ) < abs(returnedValue - k ), return current.value else return returnedValue

Closest element in binary search tree: implementation

package com.company.BST;

/**
 * Created by sangar on 3.11.18.
 */
public class ClosestElement {

    public int findClosest(TreeNode node, int k){
        if(node == null) return -1;

        int currentValue = (int)node.getValue();

        if(currentValue == k) return currentValue;

        if(currentValue > k){
            if(node.getLeft() == null) return currentValue;

            //Find closest on left subtree
            int closest = findClosest(node.getLeft(), k);
            if(Math.abs(closest - k) > Math.abs(currentValue - k)){
                return currentValue;
            }
            return closest;
        }
        else {
            if (node.getRight() == null) return currentValue;

            //Find closest on right subtree
            int closest = findClosest(node.getRight(), k);
            if (Math.abs(closest - k) 
				> Math.abs(currentValue - k)) {
                return currentValue;
            }
            return closest;
        }
    }
}
package com.company.BST;

/**
 * Created by sangar on 21.10.18.
 */
public class TreeNode<T> {
    private T value;
    private TreeNode left;
    private TreeNode right;

    public TreeNode(T value) {
        this.value = value;
        this.left = null;
        this.right = null;
    }

    public T getValue(){
        return this.value;
    }
    public TreeNode getRight(){
        return this.right;
    }
    public TreeNode getLeft(){
        return this.left;
    }

    public void setValue(T value){
        this.value = value;
    }

    public void setRight(TreeNode node){
        this.right = node;
    }

    public void setLeft(TreeNode node){
        this.left = node;
    }
}

package test;

import com.company.BST.BinarySearchTree;
import com.company.BST.ClosestElement;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

/**
 * Created by sangar on 23.9.18.
 */
public class ClosestElementTest {

    ClosestElement tester = new ClosestElement();

    @Test
    public void closestElementTest() {

        BinarySearchTree<Integer> binarySearchTree =
						new BinarySearchTree<>();
        binarySearchTree.insert(10);
        binarySearchTree.insert(8);
        binarySearchTree.insert(15);
        binarySearchTree.insert(12);
        binarySearchTree.insert(6);
        binarySearchTree.insert(9);

        assertEquals(6,
			tester.findClosest(binarySearchTree.getRoot(),1));
    }
}

Complexity of algorithm to find closest element in a binary search tree is O(n) if tree is completely skewed.

Please share if there is something wrong or missing. If you are preparing for interviews, please signup for free interview material.