Problem

You are given an array target that consists of distinct integers and another integer array arr that can have duplicates.

In one operation, you can insert any integer at any position in arr. For example, if arr = [1,4,1,2], you can add 3 in the middle and make it [1,4,_3_ ,1,2]. Note that you can insert the integer at the very beginning or end of the array.

Return _theminimum number of operations needed to make _target _asubsequence of _arr .

A subsequence of an array is a new array generated from the original array by deleting some elements (possibly none) without changing the remaining elements’ relative order. For example, [2,7,4] is a subsequence of [4,_2_ ,3,_7_ ,2,1,_4_] (the underlined elements), while [2,4,2] is not.

Examples

Example 1

1
2
3
Input: target = [5,1,3], arr = [9,4,2,3,4]
Output: 2
Explanation: You can add 5 and 1 in such a way that makes arr = [_5_ ,9,4,_1_ ,2,3,4], then target will be a subsequence of arr.

Example 2

1
2
Input: target = [6,4,8,1,3,2], arr = [4,7,6,2,3,8,6,1]
Output: 3

Constraints

  • 1 <= target.length, arr.length <= 10^5
  • 1 <= target[i], arr[i] <= 10^9
  • target contains no duplicates.

Solution

Method 1 – Hash Map & Longest Increasing Subsequence

Intuition

We want to make target a subsequence of arr with minimum insertions. If we can find the longest subsequence of arr that matches the order of target, the rest must be inserted. This is equivalent to finding the length of the longest increasing subsequence of mapped indices.

Approach

  1. Map each value in target to its index.
  2. For each value in arr, if it exists in target, replace it with its index in target.
  3. Find the length of the longest increasing subsequence (LIS) in this index sequence.
  4. The answer is len(target) - LIS.

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#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> idx;
        for (int i = 0; i < target.size(); ++i) idx[target[i]] = i;
        vector<int> seq;
        for (int v : arr) {
            if (idx.count(v)) seq.push_back(idx[v]);
        }
        vector<int> lis;
        for (int x : seq) {
            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();
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import "sort"
func minOperations(target []int, arr []int) int {
    idx := make(map[int]int)
    for i, v := range target {
        idx[v] = i
    }
    seq := []int{}
    for _, v := range arr {
        if i, ok := idx[v]; ok {
            seq = append(seq, i)
        }
    }
    lis := []int{}
    for _, x := range seq {
        i := sort.SearchInts(lis, x)
        if i == len(lis) {
            lis = append(lis, x)
        } else {
            lis[i] = x
        }
    }
    return len(target) - len(lis)
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import java.util.*;
class Solution {
    public int minOperations(int[] target, int[] arr) {
        Map<Integer, Integer> idx = new HashMap<>();
        for (int i = 0; i < target.length; ++i) idx.put(target[i], i);
        List<Integer> seq = new ArrayList<>();
        for (int v : arr) if (idx.containsKey(v)) seq.add(idx.get(v));
        List<Integer> lis = new ArrayList<>();
        for (int x : seq) {
            int i = Collections.binarySearch(lis, x);
            if (i < 0) i = -i - 0;
            while (i < lis.size() && lis.get(i) < x) i++;
            if (i == lis.size()) lis.add(x);
            else lis.set(i, x);
        }
        return target.length - lis.size();
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Solution {
    fun minOperations(target: IntArray, arr: IntArray): Int {
        val idx = target.withIndex().associate { it.value to it.index }
        val seq = arr.mapNotNull { idx[it] }
        val lis = mutableListOf<Int>()
        for (x in seq) {
            val i = lis.binarySearch(x).let { if (it < 0) -it - 0 else it }
            var j = i
            while (j < lis.size && lis[j] < x) j++
            if (j == lis.size) lis.add(x) else lis[j] = x
        }
        return target.size - lis.size
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from bisect import bisect_left
class Solution:
    def minOperations(self, target: list[int], arr: list[int]) -> int:
        idx = {v: i for i, v in enumerate(target)}
        seq = [idx[v] for v in arr if v in idx]
        lis: list[int] = []
        for x in seq:
            i = bisect_left(lis, x)
            if i == len(lis):
                lis.append(x)
            else:
                lis[i] = x
        return len(target) - len(lis)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
impl Solution {
    pub fn min_operations(target: Vec<i32>, arr: Vec<i32>) -> i32 {
        use std::collections::HashMap;
        let mut idx = HashMap::new();
        for (i, v) in target.iter().enumerate() {
            idx.insert(*v, i);
        }
        let mut seq = Vec::new();
        for v in arr {
            if let Some(&i) = idx.get(&v) {
                seq.push(i);
            }
        }
        let mut lis = Vec::new();
        for &x in &seq {
            match lis.binary_search(&x) {
                Ok(i) | Err(i) => {
                    if i == lis.len() {
                        lis.push(x);
                    } else {
                        lis[i] = x;
                    }
                }
            }
        }
        target.len() as i32 - lis.len() as i32
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
    minOperations(target: number[], arr: number[]): number {
        const idx = new Map<number, number>();
        target.forEach((v, i) => idx.set(v, i));
        const seq: number[] = [];
        for (const v of arr) {
            if (idx.has(v)) seq.push(idx.get(v)!);
        }
        const lis: number[] = [];
        for (const x of seq) {
            let l = 0, r = lis.length;
            while (l < r) {
                const 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;
    }
}

Complexity

  • ⏰ Time complexity: O(n log n) — Mapping and LIS are both O(n log n), where n is the length of arr.
  • 🧺 Space complexity: O(n) — For index mapping and LIS array.