1187. 使数组严格递增
关键词:动态规划、数组、递增序列
题目来源:1187. 使数组严格递增 - 力扣(Leetcode)
题目描述
T动态规划
给你两个整数数组 arr1
和 arr2
,返回使 arr1
严格递增所需要的最小「操作」数(可能为 0)。
每一步「操作」中,你可以分别从 arr1
和 arr2
中各选出一个索引,分别为 i
和 j
,0 <= i < arr1.length
和 0 <= j < arr2.length
,然后进行赋值运算 arr1[i] = arr2[j]
。
如果无法让 arr1
严格递增,请返回 -1
。
输入:arr1 = [1,5,3,6,7], arr2 = [1,3,2,4]
输出:1
输入:arr1 = [1,5,3,6,7], arr2 = [4,3,1]
输出:2
输入:arr1 = [1,5,3,6,7], arr2 = [1,6,3,3]
输出:-1
解释:无法使 arr1 严格递增。
数据范围
1 <= arr1.length, arr2.length <= 2000
0 <= arr1[i], arr2[i] <= 10^9
朴素求解
(后续讨论,数组下标均从1开始,代码中数组下标依题目从0开始,注意转换)
先考虑能不能构成递增数组。
对于每一个数都需要考虑要不要替换,假设当前考虑到a[i]
-
若保留a[i],则a[i]至少要大于前i-1个数构成的递增数组的末尾值,否则不能保留
前i-1个数构成的递增数组可能有多个,对应的末尾值也有多个,为了尽量保留a[i],取最小的末尾值进行比较即可。
-
若替换a[i],则用于替换的元素必须大于前i-1个数构成的递增数组的末尾值,不存在这样的元素则不能替换
前i-1个数构成的递增数组可能有多个,对应的末尾值也有多个,为了尽可能的使得后面好构成递增数组,当前用于替换的元素应该尽可能小,故取最小的末尾值进行比较即可。
始终记住,我们只需要尽可能地凑出一个答案即可,所以上述的末尾值均取最小,从而使得后续尽可能地构造递增数组。
上述两种情况都用到“最小末尾值”,于是“记录末尾最小值”,设f[i]=前i个元素构成的所有递增数组中的末尾值的最小值。当前i个数(经过多次替换)不能构成递增数组时,f[i]即为INF。
若保留a[i],则第i个位置仍为a[i],若替换a[i],则第i个位置为替换后的元素,f(i)取二者的较小值。
再考虑最小操作次数。
由于f[i]的值已经被定义为“最小末尾值”,因此需要增加一维用于记录操作次数,对数组f修改如下
设f(i,j)=前i个数,经过j次替换后,得到的递增数组的末尾元素的最小值,对于a[i]
- 若保留a[i],则a[i]必须严格大于f(i-1, j),则f(i,j)=a[i]
- 若替换a[i],则替换后的元素必须严格大于f(i-1, j),且尽可能小,则f(i,j)为替换后的元素
同样,若前i个数无法通过j次替换得到严格递增数组,则将f(i,j)标记为INF。于是,第一个不等于INF的f(n, j)即为最终答案。
int makeArrayIncreasing(vector<int> &arr1, vector<int> &arr2) {
int INF = 0x3f3f3f3f;
// 预处理arr2:排序去重
sort(arr2.begin(), arr2.end());
arr2.erase(unique(arr2.begin(), arr2.end()), arr2