得到子序列的最少操作次数
难度:
标签:
题目描述
代码结果
运行时间: 149 ms, 内存: 40.3 MB
/* 思路: 与普通Java实现类似, 我们使用Java Stream API简化代码.
我们仍然使用一个map记录target中每个元素的位置. 然后通过Stream操作过滤出arr中的有效元素, 并映射到target中的位置. 最后我们计算这些位置的最长递增子序列(LIS), 并计算需要插入的次数.
*/
import java.util.*;
import java.util.stream.Collectors;
public class SolutionStream {
public int minOperations(int[] target, int[] arr) {
Map<Integer, Integer> map = IntStream.range(0, target.length)
.boxed()
.collect(Collectors.toMap(i -> target[i], i -> i));
List<Integer> lis = Arrays.stream(arr)
.filter(map::containsKey)
.map(map::get)
.collect(Collectors.toCollection(ArrayList::new));
List<Integer> result = new ArrayList<>();
for (int num : lis) {
int pos = Collections.binarySearch(result, num);
if (pos < 0) {
pos = -(pos + 1);
}
if (pos == result.size()) {
result.add(num);
} else {
result.set(pos, num);
}
}
return target.length - result.size();
}
}
解释
方法:
该题解采用了贪心算法和最长递增子序列(LIS)的概念。首先,创建一个映射将 target 中的值和其索引关联起来。然后,遍历 arr 数组,保留那些在 target 中出现的元素,并将它们转换为在 target 中的索引,存入一个新的数组 lis 中。接下来,利用贪心和二分查找的方法来找出 lis 中的最长递增子序列的长度。最后,由于 target 是一个没有重复元素的数组,且要求 arr 的子序列与 target 相同,因此 arr 至少需要添加的元素个数等于 target 的长度减去 lis 的最长递增子序列的长度。
时间复杂度:
O(n + m logk)
空间复杂度:
O(n + k)
代码细节讲解
🦆
在使用贪心算法和最长递增子序列(LIS)求解时,为什么首先需要将arr数组中的元素转换为它们在target中的索引?
▷🦆
为什么在处理LIS时选择使用二分查找方法,直接追加到dp数组的尾部或替换已存在的最小可能值有什么优势?
▷🦆
给定的解法中,dp数组的最终长度代表了什么?它如何决定需要的最小操作次数?
▷🦆
如果arr数组完全不包含target数组中的任何元素,该算法的行为将如何变化?
▷