Given two integer arrays, target
and arr
, your goal is to make target
a subsequence of arr
using the minimum number of insert operations. In each operation, you can insert any integer at any position in arr
. You are not allowed to delete or modify elements in arr
.
A subsequence means you can remove some (or no) elements from arr
so that the remaining elements, in order, are exactly equal to target
.
target
and arr
contain unique integers.target
must appear in the same order in arr
for it to be a subsequence.arr
; each element can be used at most once in forming the subsequence.
The first idea that comes to mind is to check, for each element in target
, whether it exists in arr
in the required order. If not, we need to insert it. However, scanning through arr
many times is inefficient.
A brute-force approach would be to try all possible insertions, but that quickly becomes infeasible for large arrays. Instead, we realize that the problem is similar to finding the Longest Common Subsequence (LCS) between the two arrays, since the more elements of target
that already appear in order in arr
, the fewer insertions we need.
However, since both arrays contain unique elements, we can optimize LCS using a mapping and a Longest Increasing Subsequence (LIS) approach.
target
to their indicestarget
to its position. This allows us to quickly look up the intended order of elements.
arr
into a sequence of indicesarr
. For each element that is also in target
, replace it with its index from the mapping. This gives us a new array representing the order in which target
’s elements appear in arr
.
target
that appears in arr
in order. The elements not in this LIS are the ones we need to insert.
len(target) - len(LIS)
.
We use a hash map for fast lookups (O(1)), and a binary search-based LIS algorithm for efficiency (O(n log n)), making the solution scalable.
Input:
target = [5,1,3]
arr = [9,4,2,3,4]
target
values to indices: {5:0, 1:1, 3:2}
arr
with its index in target
(if it exists):arr
becomes [ ] (since only 3 is in target
at index 2), so index array is [2]
target
) - 1 = 2
target
a subsequence.
target
values: O(n)arr
: O(m), where m is length of arr
This is efficient even for large inputs.
from bisect import bisect_left
class Solution:
def minOperations(self, target, arr):
pos = {num: i for i, num in enumerate(target)}
idx = [pos[num] for num in arr if num in pos]
# Find LIS on idx
lis = []
for x in idx:
i = bisect_left(lis, x)
if i == len(lis):
lis.append(x)
else:
lis[i] = x
return len(target) - len(lis)
#include <vector>
#include <unordered_map>
#include <algorithm>
using namespace std;
class Solution {
public:
int minOperations(vector<int>& target, vector<int>& arr) {
unordered_map<int, int> pos;
for (int i = 0; i < target.size(); ++i)
pos[target[i]] = i;
vector<int> idx;
for (int num : arr)
if (pos.count(num))
idx.push_back(pos[num]);
vector<int> lis;
for (int x : idx) {
auto it = lower_bound(lis.begin(), lis.end(), x);
if (it == lis.end())
lis.push_back(x);
else
*it = x;
}
return target.size() - lis.size();
}
};
import java.util.*;
class Solution {
public int minOperations(int[] target, int[] arr) {
Map<Integer, Integer> pos = new HashMap<>();
for (int i = 0; i < target.length; ++i)
pos.put(target[i], i);
List<Integer> idx = new ArrayList<>();
for (int num : arr)
if (pos.containsKey(num))
idx.add(pos.get(num));
List<Integer> lis = new ArrayList<>();
for (int x : idx) {
int i = Collections.binarySearch(lis, x);
if (i < 0) i = -(i + 1);
if (i == lis.size())
lis.add(x);
else
lis.set(i, x);
}
return target.length - lis.size();
}
}
var minOperations = function(target, arr) {
const pos = new Map();
for (let i = 0; i < target.length; ++i) pos.set(target[i], i);
const idx = [];
for (const num of arr) {
if (pos.has(num)) idx.push(pos.get(num));
}
const lis = [];
for (const x of idx) {
let l = 0, r = lis.length;
while (l < r) {
let m = (l + r) >> 1;
if (lis[m] < x) l = m + 1;
else r = m;
}
if (l === lis.length) lis.push(x);
else lis[l] = x;
}
return target.length - lis.length;
};
By recognizing that this problem is about minimizing insertions to form a subsequence, we efficiently reduce it to finding the Longest Common Subsequence (LCS). Because the arrays have unique elements, we can map arr
to target
indices and use a Longest Increasing Subsequence (LIS) algorithm for speed. This approach is both elegant and efficient, leveraging hash maps and binary search to achieve optimal performance.