给你两个整数数组 arr1 和 arr2,返回使 arr1 严格递增所需要的最小「操作」数(可能为 0)。
每一步「操作」中,你可以分别从 arr1 和 arr2 中各选出一个索引,分别为 i 和 j,0 <= i < arr1.length 和 0 <= j < arr2.length,然后进行赋值运算 arr1[i] = arr2[j]。
如果无法让 arr1 严格递增,请返回 -1。
示例 1:
输入:arr1 = [1,5,3,6,7], arr2 = [1,3,2,4]
输出:1
解释:用 2 来替换 5,之后 arr1 = [1, 2, 3, 6, 7]。
示例 2:
输入:arr1 = [1,5,3,6,7], arr2 = [4,3,1]
输出:2
解释:用 3 来替换 5,然后用 4 来替换 3,得到 arr1 = [1, 3, 4, 6, 7]。
示例 3:
输入: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
链接:https://leetcode-cn.com/problems/make-array-strictly-increasing
对于这道题来说,需要从 i 推到 i+1.
状态很明显了:
dp[i][j] 表示在第 i 个位置以 arr2[j] 或 arr1[i] 结尾的最小操作数。
这里当 j == m 时表示以 arr1[i] 结尾,也就是不换。
我们可以用tmp表示当前状态结尾的数。
如果arr1[i+1] > tmp,i+1位置可以选择不换。对于 dp[i][j] 可以推出 dp[i+1][m]. 即dp[i+1][m] = dp[i][j].
选择i+1位置选择换,那么现在已知当前结尾的值为tmp,必须得从arr2找比tmp大的元素换。当然这个替换的元素越小越好。因此可以想到用二分。
令 idx 为 upper_bound (arr2, tmp) 的索引。
对于当前位置的每个tmp,如果idx存在,就可以更新 i+1 位置。
dp[i+1][idx] = dp[i][j].
上面两种状态转移方程都是取最小。
接下来考虑初始条件:
我们可以初始化dp为-1,表示该状态不存在严格递增。
很容易可以分析出 dp[0][m] = 0, dp[0][j] = 1.
这一道题就写完了。
需要注意的是,我们必须写成 i -> i+1 而不是 i-1 -> i.
如果按照后者的写法,我们需要获取 i-1 状态的结尾值才能更新当前状态。这样很不方便。
而如果按照前者的写法,我们可以获取当前状态的结尾值更新下一个状态。这也是这道题的难点之一。
另外,可以对arr2做一个排序+去重的优化。
class Solution {
public:
int makeArrayIncreasing(vector<int>& arr1, vector<int>& arr2) {
sort(arr2.begin(), arr2.end());
int n = arr1.size();
int m = unique(arr2.begin(), arr2.end())-arr2.begin();
int dp[n+2][m+2]; //dp[i][m]表示不换
memset(dp,-1,sizeof(dp));
dp[0][m] = 0;
for(int i = 0;i < m;i++) dp[0][i] = 1;
for(int i = 0;i < n-1;i++)
{
for(int j = 0;j <= m;j++)
{
if(dp[i][j] == -1) continue;
int tmp = (j==m?arr1[i]:arr2[j]); //当前i位置的值
//no 不换i+1的值
if(arr1[i+1] > tmp && (dp[i+1][m] == -1 || dp[i+1][m] > dp[i][j]))
{
dp[i+1][m] = dp[i][j];
}
//do 换i+1的值
int idx = upper_bound(arr2.begin(), arr2.begin()+m, tmp)-arr2.begin();
if(idx < m && (dp[i+1][idx] == -1 || dp[i+1][idx] > dp[i][j]+1))
dp[i+1][idx] = dp[i][j]+1;
}
}
int ans = -1;
for(int i = 0;i <= m;i++)
{
if(dp[n-1][i] == -1) continue;
if(ans == -1 || ans > dp[n-1][i])
ans = dp[n-1][i];
}
return ans;
}
};