本文已参与「新人创作礼」活动,一起开启掘金创作之路。
@TOC
力扣LeetCode-1713. 得到子序列的最少操作次数
Problem Description
给你一个数组 ,包含若干 互不相同 的整数,以及另一个整数数组 , 可能 包含重复元素。
每一次操作中,你可以在 的任意位置插入任一整数。比方说,如果 ,那么你可以在中间添加 得到 。你可以在数组最开始或最后面添加整数。
请你返回 最少 操作次数,使得 成为 的一个子序列。
一个数组的 子序列 指的是删除原数组的某些元素(可能一个元素都不删除),同时不改变其余元素的相对顺序得到的数组。比方说, 是 的子序列(加粗元素),但 不是子序列。
Tips
- 不包含任何重复元素。
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
解题思路
做这题时不难想到最长递增子序列这道题。如果没看过的可以先看一下。
题目描述中特意说明了数组互不相同,那么我们是否可以把数组映射一下呢?
如果能够把数组映射成单调递增的另一个数组,那么不就变成上一道题了吗
关键在于如何映射。正好,数组中元素的下标是递增的,因此我们可以把中的每一个数映射成它的下标,就变成了最长递增子序列问题。
所以直接用map存一下中的数和它的下标即可。
公共子序列越长,需要删除的就越少()
具体如何实现可以参考一下代码。
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…