力扣LeetCode-1713. 得到子序列的最少操作次数-题解-最长递增子序列

197 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

@TOC

力扣LeetCode-1713. 得到子序列的最少操作次数

传送门

Problem Description

给你一个数组 targettarget ,包含若干 互不相同 的整数,以及另一个整数数组 arrarrarrarr 可能 包含重复元素。

每一次操作中,你可以在 arrarr 的任意位置插入任一整数。比方说,如果 arr=[1,4,1,2]arr = [1,4,1,2] ,那么你可以在中间添加 33 得到 [1,4,3,1,2][1,4,3,1,2] 。你可以在数组最开始或最后面添加整数。

请你返回 最少 操作次数,使得 targettarget 成为 arrarr 的一个子序列。

一个数组的 子序列 指的是删除原数组的某些元素(可能一个元素都不删除),同时不改变其余元素的相对顺序得到的数组。比方说,[2,7,4][2,7,4][4,2,3,7,2,1,4][4,2,3,7,2,1,4] 的子序列(加粗元素),但 [2,4,2][2,4,2] 不是子序列。

Tips

  • 1target.length,arr.length1051 \leq target.length, arr.length \leq 10^5
  • 1target[i],arr[i]1091 \leq target[i], arr[i] \leq 10^9
  • targettarget 不包含任何重复元素。

Sample I

输入:target = [5,1,3], arr = [9,4,2,3,4] 输出:2 解释:你可以添加 5 和 1 ,使得 arr 变为 [5,9,4,1,2,3,4] ,target 为 arr 的子序列。

Sample II

输入:target = [6,4,8,1,3,2], arr = [4,7,6,2,3,8,6,1] 输出:3

解题思路

做这题时不难想到最长递增子序列这道题。如果没看过的可以先看一下。

题目描述中特意说明了targettarget数组互不相同,那么我们是否可以把targettarget数组映射一下呢?

如果能够把targettarget数组映射成单调递增的另一个数组,那么不就变成上一道题了吗

关键在于如何映射。正好,数组中元素的下标是递增的,因此我们可以把targettarget中的每一个数映射成它的下标,就变成了最长递增子序列问题。

所以直接用map存一下targettarget中的数和它的下标即可。

公共子序列越长,需要删除的就越少(需要删除数=总长度可保留数需要删除数 = 总长度 - 可保留数

具体如何实现可以参考一下代码。


AC代码

int d[100010]={0};
class Solution
{
public:
    int minOperations(vector<int> &target, vector<int> &arr)
    {
        int len=0; // d的初始长度
        map<int,int>loc;
        for(int i=0;i<target.size();i++)
        {
            loc[target[i]]=i; // 记录下target中的元素和它的下标的对应关系
        }
        vector<int>nums; // arr中可能有target中不存在的数,把nums中在target中存在的数映射成该数在target中的下标
        for(int i=0;i<arr.size();i++)
        {
            if(loc.count(arr[i])) // 如果在target中存在
            {
                nums.push_back(loc[arr[i]]);
            }
        }
        if(nums.size()) // 如果非空
        {
            d[len++]=nums[0]; // 第一个元素一定可以放入
            for(int i=1;i<nums.size();i++) // 遍历
            {
                int thisNum=nums[i]; // 这个数
                if(thisNum>d[len-1]) // 如果大于d中的最后一个数
                {
                    d[len++]=thisNum; // 添加到后面
                }
                else // 否则
                {
                    int *it=lower_bound(d, d+len, thisNum); // 找到第一个大于等于这个数的位置
                    *it = thisNum; // 用这个数替换原本比它大的数。
                }
            }
        }
        return target.size()-len; // 需要删除数 = 总长度 - 可保留数
    }
};

同步发文于我的CSDN,原创不易,转载请附上原文链接哦~
Tisfy:letmefly.blog.csdn.net/article/det…