1713. 得到子序列的最少操作次数

题目描述

原题链接
给你一个数组 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;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值