Open In App
Related Articles

Pair with minimum absolute difference after solving each query

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Report issue
Report

Given Q queries and an empty list. 

The queries can be of two types: 

  1. addToList(x) : Add x to your list.
  2. removeFromList(x) : Remove x from your list.

The task is, after each query, you have to print the minimum value of abs(list[i]-list[j]) where, 0<=i<=n, 0<=j<=n and i ? j and n is the total number of elements present in the list. 

Examples

Input : Q = 4 
addToList(1), insert 1 in our set 
addToList(5), insert 5 in our set 
addToList(3), insert 3 in our set 
removeFromList(3), delete 3 in our set 

Output
0, as we have only one element {1} in our set. 
4, as we have {1, 5} minimum difference between all possible pairs is 4 (5-1) 
2, as we have {1, 3, 5} minimum difference between all possible pairs is 2 (3-1) 
4, as we have {1, 5} minimum difference between all possible pairs is 4 (5-1) 

Method 1: 
The idea is to use set-in C++ to store all the elements so that insertion or deletion can be done in O(log(n)) with keeping the elements in sorted order. Now, to find the minimum difference, we have to iterate over the whole set and find the difference between only adjacent elements as elements are in sorted order i.e, the minimum difference will always be contributed by adjacent elements. This can be done in O(n) time complexity. So, the overall time complexity of this approach will be (q*log(n)+q*n). 

Method 2: 
We can use multiset to store and maintain all the elements and map to store the difference between the adjacent elements in sorted order, where, map’s key represents the difference between adjacent elements and the corresponding map’s value represent the frequency of occurrence of this difference. 

Below is the complete algorithm: 

First, insert two sentinel values in the multi-set. Let’s say (-10^9+7 and 10^9+7) and initialize the map with the difference of this sentinel value, i.e 2*10^7+7, and set its frequency to be 1. 
Now we have two types of queries: 

  1. Insertion Query: For an insertion query, first insert the value inset. After inserting the element, we will have to also update the differences of adjacent elements in the map. To do this, find the left and right values of the newly inserted element in the set. Earlier when this new value was not inserted in the set, abs(right-left) is contributing to the different terms in the map. To update the map after inserting the new element, first, remove the previous difference abs(right-left) as a new value is inserted between the elements left and right and add two differences to the map. i.e, abs(right-x) and abs(x-left).
  2. Deletion Query: In case of deletion of a value from the set. First, find the left and right elements of the elements that needed to be deleted, say x. Then according to the above algorithm, reduce the frequency of abs(right-x) and abs(left-x) and increment the frequency of abs(right-left).

So, each query can be solved in log(n) time complexity. Therefore, overall complexity will be O(q*log(n)).

Implementation:

C++

// C++ implementation of above approach
#include <bits/stdc++.h>
#define ll long long int
const ll MOD = 1e9 + 7;
using namespace std;
 
// Function to add an element into the list
void addToList(int x, multiset<ll>& s, map<ll, ll>& mp)
{
    // firstly insert value in set
    s.insert(x);
 
    // find left and right value of inserted value.
    ll left, right;
 
    // now here is logic explained below
    left = *(--s.find(x));
    right = *(++s.find(x));
    mp[abs(left - x)]++;
    mp[abs(right - x)]++;
    mp[abs(left - right)]--;
    if (mp[abs(left - right)] == 0)
        mp.erase(abs(left - right));
}
 
// Function to remove an element from the list
void removeFromList(int x, multiset<ll>& s, map<ll, ll>& mp)
{
    ll left, right;
 
    // Find left element of number that we want to delete.
    left = *(--s.find(x));
 
    // Find right element of number that we want to delete.
    right = *(++s.find(x));
 
    // remove x from set
    s.erase(s.find(x));
 
    // Again this will explain below in article.
    mp[abs(left - x)]--;
    if (mp[abs(left - x)] == 0)
        mp.erase(abs(left - x));
    mp[abs(right - x)]--;
    if (mp[abs(right - x)] == 0)
        mp.erase(abs(right - x));
 
    mp[abs(left - right)]++;
}
 
// Driver code
int main()
{
 
    int q = 4;
 
    // define set to store all values.
    multiset<ll> s;
 
    // define map to store difference in sorted
    map<ll, ll> mp;
 
    // initialize set with sentinel values
    s.insert(-MOD);
    s.insert(MOD);
 
    // maintain freq of difference in map so, here initially
    // difference b/w sentinel value and its freq is one.
    mp[2 * MOD] = 1;
 
    // 1st query 1 1 i.e, include 1 in our set
    addToList(1, s, mp);
 
    // As now we have only one element {-10^9+7, 1, 10^9+7}
    // (except two are sentinel values)
    // so minimum among all pair is zero
    cout << 0 << endl;
 
    // 2nd query 1 5 i.e, include 5 in our set.
    addToList(5, s, mp);
 
    // find smallest difference possible
    // as it should be in beginning of map
    cout << mp.begin()->first << endl;
 
    // 3rd query 1 3 i.e, include 3 in our set.
    addToList(3, s, mp);
 
    // find smallest difference possible
    // as it should be in beginning of map
    cout << mp.begin()->first << endl;
 
    // 4th query 2 3 i.e, remove 3 from our list
    removeFromList(3, s, mp);
 
    cout << mp.begin()->first << endl;
 
 return 0;
}

                    

Java

import java.util.*;
 
public class Main {
  static final long MOD = 1000000007;
 
  public static void addToList(int x, TreeSet<Long> s,
                               TreeMap<Long, Long> mp)
  {
    // firstly insert value in set
    s.add((long)x);
 
    // find left and right value of inserted value.
    long left, right;
 
    // now here is logic explained below
    left = s.lower((long)x);
    right = s.higher((long)x);
    mp.merge(Math.abs(left - x), 1L, Long::sum);
    mp.merge(Math.abs(right - x), 1L, Long::sum);
    mp.merge(Math.abs(left - right), -1L, Long::sum);
    if (mp.get(Math.abs(left - right)) == 0)
      mp.remove(Math.abs(left - right));
  }
 
  public static void removeFromList(int x, TreeSet<Long> s,
                                    TreeMap<Long, Long> mp)
  {
    long left, right;
 
    // Find left element of number that we want to delete.
    left = s.lower((long)x);
 
    // Find right element of number that we want to delete.
    right = s.higher((long)x);
 
    // remove x from set
    s.remove((long)x);
 
    // Again this will explain below in article.
    mp.merge(Math.abs(left - x), -1L, Long::sum);
    if (mp.get(Math.abs(left - x)) == 0)
      mp.remove(Math.abs(left - x));
    mp.merge(Math.abs(right - x), -1L, Long::sum);
    if (mp.get(Math.abs(right - x)) == 0)
      mp.remove(Math.abs(right - x));
 
    mp.merge(Math.abs(left - right), 1L, Long::sum);
  }
 
  public static void main(String[] args) {
    int q = 4;
 
    // define set to store all values.
    TreeSet<Long> s = new TreeSet<>();
 
    // define map to store difference in sorted
    TreeMap<Long, Long> mp = new TreeMap<>();
 
    // initialize set with sentinel values
    s.add(-MOD);
    s.add(MOD);
 
    // maintain freq of difference in map so, here initially
    // difference b/w sentinel value and its freq is one.
    mp.merge(2 * MOD, 1L, Long::sum);
 
    // 1st query 1 1 i.e, include 1 in our set
    addToList(1, s, mp);
 
    // As now we have only one element {-10^9+7, 1, 10^9+7}
    // (except two are sentinel values)
    // so minimum among all pair is zero
    System.out.println(0);
 
    // 2nd query 1 5 i.e, include 5 in our set.
    addToList(5, s, mp);
 
    // find smallest difference possible
    // as it should be in beginning of map
    System.out.println(mp.firstKey());
 
    // 3rd query 1 3 i.e, include 3 in our set.
    addToList(3, s, mp);
 
    // find smallest difference possible
    // as it should be in beginning of map
    System.out.println(mp.firstKey());
 
    // 4th query 2 3 i.e, remove 3 from our list
    removeFromList(3, s, mp);
 
    System.out.println(mp.firstKey());
  }
}

                    

Python3

# Python Equivalent
import bisect
 
MOD = 1000000007
 
def addToList(x, s, mp):
  # firstly insert value in set
  bisect.insort(s, x)
 
  # find left and right value of inserted value.
  left, right = -MOD, MOD
 
  # find left element of the inserted value
  for i in range(len(s)):
    if s[i] == x:
      if i == 0:
        left = -MOD
      else:
        left = s[i-1]
 
      break
 
  # find right element of the inserted value
  for i in range(len(s)):
    if s[i] == x:
      if i == len(s) - 1:
        right = MOD
      else:
        right = s[i+1]
 
      break
 
  # update the map with abs difference and freq
  mp[abs(left - x)] = mp.get(abs(left - x), 0) + 1
  mp[abs(right - x)] = mp.get(abs(right - x), 0) + 1
  mp[abs(left - right)] =  mp.get(abs(left - right), 0) - 1
 
  if mp[abs(left - right)] == 0:
    del mp[abs(left - right)]
 
def removeFromList(x, s, mp):
  # Find left element of number that we want to delete.
  left = s[bisect.bisect_left(s, x) - 1]
 
  # Find right element of number that we want to delete.
  right = s[bisect.bisect_right(s, x)]
 
  # remove x from set
  s.remove(x)
 
  # update the map with abs difference and freq
  mp[abs(left - x)] = mp.get(abs(left - x), 0) - 1
  if mp[abs(left - x)] == 0:
    del mp[abs(left - x)]
  mp[abs(right - x)] = mp.get(abs(right - x), 0) - 1
  if mp[abs(right - x)] == 0:
    del mp[abs(right - x)]
  mp[abs(left - right)] =  mp.get(abs(left - right), 0) + 1
 
def main():
  q = 4
 
  # define set to store all values.
  s = []
 
  # define map to store difference in sorted
  mp = {}
 
  # initialize set with sentinel values
  bisect.insort(s, -MOD)
  bisect.insort(s, MOD)
 
  # maintain freq of difference in map so, here initially
  # difference b/w sentinel value and its freq is one.
  mp[2 * MOD] = 1
 
  # 1st query 1 1 i.e, include 1 in our set
  addToList(1, s, mp)
 
  # As now we have only one element {-10^9+7, 1, 10^9+7}
  # (except two are sentinel values)
  # so minimum among all pair is zero
  print(0)
 
  # 2nd query 1 5 i.e, include 5 in our set.
  addToList(5, s, mp)
 
  # find smallest difference possible
  # as it should be in beginning of map
  print(min(mp.keys()))
 
  # 3rd query 1 3 i.e, include 3 in our set.
  addToList(3, s, mp)
 
  # find smallest difference possible
  # as it should be in beginning of map
  print(min(mp.keys()))
 
  # 4th query 2 3 i.e, remove 3 from our list
  removeFromList(3, s, mp)
 
  print(min(mp.keys()))
 
if __name__ == "__main__":
  main()

                    

C#

using System;
using System.Collections.Generic;
using System.Linq;
 
class Program
{
    const int MOD = 1000000007;
 
    static void AddToList(int x, SortedSet<int> s, Dictionary<int, int> mp)
    {
        // Firstly insert the value in the set
        s.Add(x);
 
        int left = -MOD, right = MOD;
 
        // Find the left element of the inserted value
        foreach (var val in s)
        {
            if (val < x)
            {
                left = val;
            }
            else
            {
                break;
            }
        }
 
        // Find the right element of the inserted value
        foreach (var val in s.Reverse())
        {
            if (val > x)
            {
                right = val;
            }
            else
            {
                break;
            }
        }
 
        // Update the dictionary with the absolute difference and frequency
        mp[Math.Abs(left - x)] =
          mp.TryGetValue(Math.Abs(left - x), out var freq) ? freq + 1 : 1;
        mp[Math.Abs(right - x)] =
          mp.TryGetValue(Math.Abs(right - x), out freq) ? freq + 1 : 1;
        mp[Math.Abs(left - right)] =
          mp.TryGetValue(Math.Abs(left - right), out freq) ? freq - 1 : -1;
 
        if (mp[Math.Abs(left - right)] == 0)
            mp.Remove(Math.Abs(left - right));
    }
 
    static void RemoveFromList(int x, SortedSet<int> s, Dictionary<int, int> mp)
    {
        int left = -MOD, right = MOD;
 
        // Find the left and right elements of the number that we want to delete
        foreach (var val in s)
        {
            if (val < x)
            {
                left = val;
            }
            else if (val > x)
            {
                right = val;
                break;
            }
        }
 
        // Remove x from the set
        s.Remove(x);
 
        // Update the dictionary with the absolute difference and frequency
        mp[Math.Abs(left - x)] =
          mp.TryGetValue(Math.Abs(left - x), out var freq) ? freq - 1 : -1;
        if (mp[Math.Abs(left - x)] == 0)
            mp.Remove(Math.Abs(left - x));
        mp[Math.Abs(right - x)] =
          mp.TryGetValue(Math.Abs(right - x), out freq) ? freq - 1 : -1;
        if (mp[Math.Abs(right - x)] == 0)
            mp.Remove(Math.Abs(right - x));
        mp[Math.Abs(left - right)] =
          mp.TryGetValue(Math.Abs(left - right), out freq) ? freq + 1 : 1;
    }
 
    static void Main()
    {
        SortedSet<int> s = new SortedSet<int>();
        Dictionary<int, int> mp = new Dictionary<int, int>();
 
        // Initialize the set with sentinel values
        s.Add(-MOD);
        s.Add(MOD);
 
        // Maintain the frequency of differences in the map,
        // initially the difference between sentinel values has a frequency of 1.
        mp[2 * MOD] = 1;
 
        // 1st query - Add 1 to the set
        AddToList(1, s, mp);
 
        // As there is only one element {int.MinValue, 1, int.MaxValue}
        // except for the sentinel values, the minimum difference is zero.
        Console.WriteLine(0);
 
        // 2nd query - Add 5 to the set
        AddToList(5, s, mp);
 
        // Find the smallest possible difference, which should be at the beginning of the map
        Console.WriteLine(mp.Keys.Min());
 
        // 3rd query - Add 3 to the set
        AddToList(3, s, mp);
 
        // Find the smallest possible difference, which should be at the beginning of the map
        Console.WriteLine(mp.Keys.Min());
 
        // 4th query - Remove 3 from the set
        RemoveFromList(3, s, mp);
 
        Console.WriteLine(mp.Keys.Min());
    }
}

                    

Javascript

// Function to add an element into the list
function addToList(x, s, mp) {
    // firstly insert value in set
    s.add(x);
 
    // find left and right value of inserted value.
    let left, right;
 
    // now here is logic explained below
    left = Array.from(s).filter((val) => val < x).pop();
    right = Array.from(s).filter((val) => val > x)[0];
    mp[(Math.abs(left - x))] = (mp[(Math.abs(left - x))] || 0) + 1;
    mp[(Math.abs(right - x))] = (mp[(Math.abs(right - x))] || 0) + 1;
    mp[(Math.abs(left - right))] = (mp[(Math.abs(left - right))] || 0) - 1;
    if (mp[(Math.abs(left - right))] === 0)
        delete mp[(Math.abs(left - right))];
}
 
// Function to remove an element from the list
function removeFromList(x, s, mp) {
    let left, right;
 
    // Find left element of number that we want to delete.
    left = Array.from(s).filter((val) => val < x).pop();
 
    // Find right element of number that we want to delete.
    right = Array.from(s).filter((val) => val > x)[0];
 
    // remove x from set
    s.delete(x);
 
    // Again this will explain below in article.
    mp[(Math.abs(left - x))] = (mp[(Math.abs(left - x))] || 0) - 1;
    if (mp[(Math.abs(left - x))] === 0)
        delete mp[(Math.abs(left - x))];
    mp[(Math.abs(right - x))] = (mp[(Math.abs(right - x))] || 0) - 1;
    if (mp[(Math.abs(right - x))] === 0)
        delete mp[(Math.abs(right - x))];
 
    mp[(Math.abs(left - right))] = (mp[(Math.abs(left - right))] || 0) + 1;
}
 
// Driver code
let q = 4;
 
// define set to store all values.
let s = new Set();
 
// define map to store difference in sorted
let mp = {};
 
// initialize set with sentinel values
s.add(-1000000007);
s.add(1000000007);
 
// maintain freq of difference in map so, here initially
// difference b/w sentinel value and its freq is one.
mp[2000000014] = 1;
 
// 1st query 1 1 i.e, include 1 in our set
addToList(1, s, mp);
 
// As now we have only one element {-10^9+7, 1, 10^9+7}
// (except two are sentinel values)
// so minimum among all pair is zero
console.log(0);
 
// 2nd query 1 5 i.e, include 5 in our set.
addToList(5, s, mp);
 
// find smallest difference possible
// as it should be in beginning of map
console.log(Object.keys(mp)[0]);
 
// 3rd query 1 3 i.e, include 3 in our set.
addToList(3, s, mp);
 
// find smallest difference possible
// as it should be in beginning of map
console.log(Object.keys(mp)[0]);
 
 
// 4th query 2 3 i.e, remove 3 from our list
removeFromList(3, s, mp);
 
console.log(Object.keys(mp)[0]);

                    

Output
0
4
2
4


Explanation of each query: 

  1. addToList(1): As now we have only one element {-10^9+7, 1, 10^9+7} (except two are sentinel values), so minimum among all pair is zero.
  2. addToList(5): After inserting 1 and 5 to the set, set becomes {-10^9+7, 1, 5, 10^9+7} and map: mp[5-1]=1 where key represents difference and its value represents frequency.
  3. addToList(3): As here we are inserting 3. So, first, we find the left and right element of 3 in the set after insertion i.e. left = 1, right = 5. As 3 came in between 1 and 5, so we remove map[5-1]–. (as 3 came in between 1 and 5 so 5-1 will no longer minimum) And we include these differences map[3-1]++ and map[5-3]++ (because 3 came between 1 and 5, so possible minimum have two cases).
  4. removeFromList(3): Similar to of above query, here we are deleting the element. So, first, find the left and right elements to 3 i.e. left = 1, right = 5. As we are going to delete 3 which is in between 1 & 5 so the minimum difference will be affected only by 3 and 5,
before deleting ==>{1, 3, 5}, 
after deleting ==> {1, 5}.
So, map[3-1]--, map[5-3]-- and add map[5-1]++.

Time Complexity : O(qlogN), where ‘q’ is the total number of queries.
Auxiliary Space: O(q). 



Last Updated : 30 Oct, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads