题目描述
原题链接
给你一个数组 target ,包含若干 互不相同 的整数,以及另一个整数数组 arr ,arr 可能 包含重复元素。
每一次操作中,你可以在 arr 的任意位置插入任一整数。比方说,如果 arr = [1,4,1,2] ,那么你可以在中间添加 3 得到 [1,4,3,1,2] 。你可以在数组最开始或最后面添加整数。
请你返回 最少 操作次数,使得 target 成为 arr 的一个子序列。
一个数组的 子序列 指的是删除原数组的某些元素(可能一个元素都不删除),同时不改变其余元素的相对顺序得到的数组。比方说,[2,7,4] 是 [4,2,3,7,2,1,4] 的子序列(加粗元素),但 [2,4,2] 不是子序列。
示例 1:
输入:target = [5,1,3], arr = [9,4,2,3,4]
输出:2
解释:你可以添加 5 和 1 ,使得 arr 变为 [5,9,4,1,2,3,4] ,target 为 arr 的子序列。
示例 2:
输入:target = [6,4,8,1,3,2], arr = [4,7,6,2,3,8,6,1]
输出:3
提示:
1 <= target.length, arr.length <= 105
1 <= target[i], arr[i] <= 109
target 不包含任何重复元素。
题目分析
这一题换一种问法可以改为:找出arr和target的最长公共子序列,或者:找出arr中的最长子序列,使得其为target的子序列。可以用求解公共子序列的方法求解,不过容易超时,考虑到本题target的特殊性,即target中的元素不重复,可以将其改为求解最长子序列问题。
以target = [6,4,8,1,3,2], arr = [4,7,6,2,3,8,6,1]为例,找出target中target[i]和i的一一对应关系,将target变为[1,2,3,4,5,6],将arr中存在于target中的元素换成它在target中的下标,不在target中的元素删去,得到[2,1,6,5,3,1,4]。此时我们可以找arr中的最长上升子序列即可,因为只要保证其是上升子序列,它就自动是target中的子序列。
class Solution {
public:
int minOperations(vector<int>& target, vector<int>& arr) {
unordered_map<int, int> myMap;
for(int i = 0; i < target.size(); i++){
myMap[target[i]] = i;
}
vector<int> seq;
for(int i = 0; i < arr.size(); i++){
if(myMap.count(arr[i]) != 0){
seq.push_back(myMap[arr[i]]);
}
}
// vector<int> ans;
int len = 1;
vector<int> ans(seq.size() + 1, 0);
if(seq.size() == 0){
return target.size();
}
ans[1] = seq[0];
for(int i = 0; i < seq.size(); i++){
// auto it = lower_bound(ans.begin(), ans.end(), seq[i]);
// if (it != ans.end()) {
// *it = seq[i];
// }
// else {
// ans.push_back(seq[i]);
// }
if(seq[i] > ans[len]){
ans[++len] = seq[i];
}
else{
int l = 1, r = len, pos = 0;
while(l <= r){
int m = (l + r) / 2;
if(ans[m] < seq[i]){
pos = m;
l = m + 1;
}
else{
r = m - 1;
}
}
ans[pos + 1] = seq[i];
}
}
return target.size() - len;
}
};