Given two arrays a[] and b[], find the minimum number of insertions and deletions on the array a[], required to make both the arrays identical.
Note: Array b[] is sorted and all its elements are distinct, operations can be performed at any index not necessarily at the end.
Examples:
Input: a[] = [1, 2, 5, 3, 1], b[] = [1, 3, 5]
Output: 4
Explanation:
Delete 2 from a: a[] = [1, 5, 3, 1]
Insert 3 after 1: a[] = [1, 3, 5, 3, 1]
Delete the last two elements: a[] = [1, 3, 5]
Total operations = 1 + 1 + 2 = 4.Input: a[] = [1, 4], b[] = [1, 4]
Output: 0
Explanation:
Table of Content
[Naive Approach] Using Longest Common Subsequence (LCS) DP - O(n * m) Time O(n * m) Space
The idea is to find the Longest Common Subsequence (LCS) between
a[]andb[]. The elements that are not part of the LCS are either deleted froma[]or inserted intoa[]to make both arrays identical.
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
// Function to find minimum insertions
// and deletions required
int minInsAndDel(vector<int> &a, vector<int> &b)
{
int n = a.size();
int m = b.size();
// dp[i][j] stores length of LCS
vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
// Build LCS table
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
// If elements are equal
if (a[i - 1] == b[j - 1])
{
dp[i][j] = 1 + dp[i - 1][j - 1];
}
// Otherwise take maximum
else
{
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
// Length of LCS
int lcs = dp[n][m];
// Store final answer
return (n - lcs) + (m - lcs);
}
// Driver Code
int main()
{
vector<int> a = {1, 2, 5, 3, 1};
vector<int> b = {1, 3, 5};
cout << minInsAndDel(a, b);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Function to find minimum insertions
// and deletions required
int minInsAndDel(int *a, int *b, int n, int m)
{
// dp[i][j] stores length of LCS
int **dp = (int **)malloc((n + 1) * sizeof(int*));
for(int i = 0; i <= n; i++)
dp[i] = (int *)malloc((m + 1) * sizeof(int));
// Build LCS table
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
// If elements are equal
if (a[i - 1] == b[j - 1])
{
dp[i][j] = 1 + dp[i - 1][j - 1];
}
// Otherwise take maximum
else
{
dp[i][j] = (dp[i - 1][j] > dp[i][j - 1])? dp[i - 1][j] : dp[i][j - 1];
}
}
}
// Length of LCS
int lcs = dp[n][m];
// Store final answer
int ans = (n - lcs) + (m - lcs);
// Free allocated memory
for(int i = 0; i <= n; i++)
free(dp[i]);
free(dp);
return ans;
}
// Driver Code
int main()
{
int a[] = {1, 2, 5, 3, 1};
int b[] = {1, 3, 5};
int n = sizeof(a) / sizeof(a[0]);
int m = sizeof(b) / sizeof(b[0]);
printf("%d", minInsAndDel(a, b, n, m));
return 0;
}
import java.util.Arrays;
// Function to find minimum insertions
// and deletions required
public class GfG {
public static int minInsAndDel(int[] a, int[] b) {
int n = a.length;
int m = b.length;
// dp[i][j] stores length of LCS
int[][] dp = new int[n + 1][m + 1];
// Build LCS table
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
// If elements are equal
if (a[i - 1] == b[j - 1]) {
dp[i][j] = 1 + dp[i - 1][j - 1];
}
// Otherwise take maximum
else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
// Length of LCS
int lcs = dp[n][m];
// Store final answer
int ans = (n - lcs) + (m - lcs);
return ans;
}
// Driver Code
public static void main(String[] args) {
int[] a = {1, 2, 5, 3, 1};
int[] b = {1, 3, 5};
System.out.println(minInsAndDel(a, b));
}
}
def minInsAndDel(a, b):
n = len(a)
m = len(b)
# dp[i][j] stores length of LCS
dp = [[0 for _ in range(m + 1)] for _ in range(n + 1)]
# Build LCS table
for i in range(1, n + 1):
for j in range(1, m + 1):
# If elements are equal
if a[i - 1] == b[j - 1]:
dp[i][j] = 1 + dp[i - 1][j - 1]
# Otherwise take maximum
else:
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
# Length of LCS
lcs = dp[n][m]
# Store final answer
ans = (n - lcs) + (m - lcs)
return ans
# Driver Code
if __name__ == "__main__":
a = [1, 2, 5, 3, 1]
b = [1, 3, 5]
print(minInsAndDel(a, b))
using System;
public class GfG
{
public static int MinInsAndDel(int[] a, int[] b)
{
int n = a.Length;
int m = b.Length;
// dp[i][j] stores length of LCS
int[,] dp = new int[n + 1, m + 1];
// Build LCS table
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
// If elements are equal
if (a[i - 1] == b[j - 1])
{
dp[i, j] = 1 + dp[i - 1, j - 1];
}
// Otherwise take maximum
else
{
dp[i, j] = Math.Max(dp[i - 1, j], dp[i, j - 1]);
}
}
}
// Length of LCS
int lcs = dp[n, m];
// Store final answer
int ans = (n - lcs) + (m - lcs);
return ans;
}
public static void Main()
{
int[] a = { 1, 2, 5, 3, 1 };
int[] b = { 1, 3, 5 };
Console.WriteLine(MinInsAndDel(a, b));
}
}
function minInsAndDel(a, b) {
let n = a.length;
let m = b.length;
// dp[i][j] stores length of LCS
let dp = Array.from(Array(n + 1), () => Array(m + 1).fill(0));
// Build LCS table
for (let i = 1; i <= n; i++) {
for (let j = 1; j <= m; j++) {
// If elements are equal
if (a[i - 1] === b[j - 1]) {
dp[i][j] = 1 + dp[i - 1][j - 1];
}
// Otherwise take maximum
else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
// Length of LCS
let lcs = dp[n][m];
// Store final answer
let ans = (n - lcs) + (m - lcs);
return ans;
}
// Driver Code
let a = [1, 2, 5, 3, 1];
let b = [1, 3, 5];
console.log(minInsAndDel(a, b));
Output
4
Time Complexity: O(n * m)
Auxiliary Space: O(n * m)
[Expected Approach] Using Longest Increasing Subsequence (LIS) - O(n log n) Time O(n) Space
The idea is to map each element of
a[]to its position inb[](if it exists) and then find the Longest Increasing Subsequence (LIS) of this mapped sequence. Sinceb[]is sorted and contains distinct elements, the LIS represents the maximum number of elements already in the correct order, while the remaining elements are handled through insertions and deletions.
#include <algorithm>
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;
// Function to find minimum insertions
// and deletions required
int minInsAndDel(vector<int> &a, vector<int> &b)
{
int n = a.size();
int m = b.size();
// Store index of elements in b
unordered_map<int, int> mp;
for (int i = 0; i < m; i++)
{
mp[b[i]] = i;
}
// Store mapped indices
vector<int> v;
// Traverse array a
for (int x : a)
{
// If element is present in b
if (mp.count(x))
{
v.push_back(mp[x]);
}
}
// Stores LIS
vector<int> lis;
// Find LIS of mapped indices
for (int x : v)
{
// Find position using lower_bound
auto it = lower_bound(lis.begin(), lis.end(), x);
// Insert element
if (it == lis.end())
{
lis.push_back(x);
}
// Replace element
else
{
*it = x;
}
}
// Length of LCS
int len = lis.size();
// Store final answer
int res = (n - len) + (m - len);
return res;
}
// Driver Code
int main()
{
vector<int> a = {1, 2, 5, 3, 1};
vector<int> b = {1, 3, 5};
cout << minInsAndDel(a, b);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Function to find minimum insertions
// and deletions required
int minInsAndDel(int *a, int *b, int n, int m)
{
int i;
// Store index of elements in b
int *mp = (int *)malloc(100000 * sizeof(int));
for (i = 0; i < 100000; i++)
{
mp[i] = -1;
}
for (i = 0; i < m; i++)
{
mp[b[i]] = i;
}
// Store mapped indices
int *v = (int *)malloc(n * sizeof(int));
int v_size = 0;
// Traverse array a
for (i = 0; i < n; i++)
{
// If element is present in b
if (mp[a[i]] != -1)
{
v[v_size++] = mp[a[i]];
}
}
// Stores LIS
int *lis = (int *)malloc(v_size * sizeof(int));
int lis_len = 0;
// Find LIS of mapped indices
for (i = 0; i < v_size; i++)
{
int x = v[i];
int left = 0;
int right = lis_len;
while (left < right)
{
int mid = left + (right - left) / 2;
if (lis[mid] < x)
{
left = mid + 1;
}
else
{
right = mid;
}
}
// Insert element
if (left == lis_len)
{
lis[lis_len++] = x;
}
// Replace element
else
{
lis[left] = x;
}
}
// Length of LCS
int len = lis_len;
// Store final answer
int ans = (n - len) + (m - len);
free(mp);
free(v);
free(lis);
return ans;
}
// Driver Code
int main()
{
int a[] = {1, 2, 5, 3, 1};
int b[] = {1, 3, 5};
int n = sizeof(a) / sizeof(a[0]);
int m = sizeof(b) / sizeof(b[0]);
printf("%d", minInsAndDel(a, b, n, m));
return 0;
}
import java.util.*;
// Function to find minimum insertions
// and deletions required
public class GfG {
public static int minInsAndDel(int[] a, int[] b) {
int n = a.length;
int m = b.length;
// Store index of elements in b
HashMap<Integer, Integer> mp = new HashMap<>();
for (int i = 0; i < m; i++) {
mp.put(b[i], i);
}
// Store mapped indices
ArrayList<Integer> v = new ArrayList<>();
// Traverse array a
for (int x : a) {
// If element is present in b
if (mp.containsKey(x)) {
v.add(mp.get(x));
}
}
// Stores LIS
ArrayList<Integer> lis = new ArrayList<>();
// Find LIS of mapped indices
for (int x : v) {
// Find position using lower_bound
int index = Collections.binarySearch(lis, x);
if (index < 0) {
index = - (index + 1);
}
// Insert element
if (index == lis.size()) {
lis.add(x);
}
// Replace element
else {
lis.set(index, x);
}
}
// Length of LCS
int len = lis.size();
// Store final answer
int ans = (n - len) + (m - len);
return ans;
}
// Driver Code
public static void main(String[] args) {
int[] a = {1, 2, 5, 3, 1};
int[] b = {1, 3, 5};
System.out.println(minInsAndDel(a, b));
}
}
from bisect import bisect_left
# Function to find minimum insertions
# and deletions required
def minInsAndDel(a, b):
n = len(a)
m = len(b)
# Store index of elements in b
mp = {value: index for index, value in enumerate(b)}
# Store mapped indices
v = [mp[x] for x in a if x in mp]
# Stores LIS
lis = []
# Find LIS of mapped indices
for x in v:
# Find position using lower_bound
it = bisect_left(lis, x)
# Insert element
if it == len(lis):
lis.append(x)
# Replace element
else:
lis[it] = x
# Length of LCS
len_lis = len(lis)
# Store final answer
ans = (n - len_lis) + (m - len_lis)
return ans
# Driver Code
if __name__ == "__main__":
a = [1, 2, 5, 3, 1]
b = [1, 3, 5]
print(minInsAndDel(a, b))
using System;
using System.Collections.Generic;
class GfG
{
// Function to find minimum insertions
// and deletions required
static int minInsAndDel(int[] a, int[] b)
{
int n = a.Length;
int m = b.Length;
// Store index of elements in b
Dictionary<int, int> mp = new Dictionary<int, int>();
for (int i = 0; i < m; i++)
{
mp[b[i]] = i;
}
// Store mapped indices
List<int> v = new List<int>();
// Traverse array a
foreach (int x in a)
{
// If element is present in b
if (mp.ContainsKey(x))
{
v.Add(mp[x]);
}
}
// Stores LIS
List<int> lis = new List<int>();
// Find LIS of mapped indices
foreach (int x in v)
{
// Find position using BinarySearch
int idx = lis.BinarySearch(x);
idx = idx < 0? ~idx : idx;
// Insert element
if (idx == lis.Count)
{
lis.Add(x);
}
// Replace element
else
{
lis[idx] = x;
}
}
// Length of LCS
int len = lis.Count;
// Store final answer
int ans = (n - len) + (m - len);
return ans;
}
// Driver Code
static void Main(string[] args)
{
int[] a = { 1, 2, 5, 3, 1 };
int[] b = { 1, 3, 5 };
Console.WriteLine(minInsAndDel(a, b));
}
}
// Function to find minimum insertions
// and deletions required
function minInsAndDel(a, b) {
let n = a.length;
let m = b.length;
// Store index of elements in b
let mp = new Map();
for (let i = 0; i < m; i++) {
mp.set(b[i], i);
}
// Store mapped indices
let v = [];
// Traverse array a
for (let x of a) {
// If element is present in b
if (mp.has(x)) {
v.push(mp.get(x));
}
}
// Stores LIS
let lis = [];
// Find LIS of mapped indices
for (let x of v) {
// Find position using binary search
let idx = binarySearch(lis, x);
// Insert element
if (idx === lis.length) {
lis.push(x);
}
// Replace element
else {
lis[idx] = x;
}
}
// Length of LCS
let len = lis.length;
// Store final answer
let ans = (n - len) + (m - len);
return ans;
}
// Binary search function to find insertion point
function binarySearch(arr, x) {
let low = 0;
let high = arr.length - 1;
while (low <= high) {
let mid = Math.floor((low + high) / 2);
if (arr[mid] === x) {
return mid;
} else if (arr[mid] < x) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return low;
}
// Driver Code
let a = [1, 2, 5, 3, 1];
let b = [1, 3, 5];
console.log(minInsAndDel(a, b));
Output
4
Time Complexity: O(n log n)
Auxiliary Space: O(n)