使数组严格递增【LC1187】
给你两个整数数组
arr1和arr2,返回使arr1严格递增所需要的最小「操作」数(可能为 0)。每一步「操作」中,你可以分别从
arr1和arr2中各选出一个索引,分别为i和j,0 <= i < arr1.length和0 <= j < arr2.length,然后进行赋值运算arr1[i] = arr2[j]。如果无法让
arr1严格递增,请返回-1。
很难呀 需要消化(为什么有时候感觉自己很聪明 有时候感觉很笨笨)
-
思路
-
首先很容易想到的是,将
arr2排序,如果arr1[i]<=arr1[i−1]arr1[i]<=arr1[i - 1]arr1[i]<=arr1[i−1],为了满足递增我们应该将arr1[i−1]arr1[i-1]arr1[i−1]替换为arr2中小于arr1[i]arr1[i]arr1[i]的最大值【二分查找】(我就想到这里,没有想到还要用dp) -
然后,使数组
arr1前iii个元素严格递增需要的最小「操作」数可以由之前的状态转移得到【替换或者不替换,替换的值取决于下一个元素的大小(本题限制因素)】,因此可以定义状态dp[i]dp[i]dp[i]为将arr1[0:i]转化为严格递增数组,并且arr[i]arr[i]arr[i]不做替换的最小操作数-
确定 base case,初始状态的值:dp[0]=0,dp[i]=∞dp[0]=0,dp[i]= \inftydp[0]=0,dp[i]=∞
-
确定「状态」,也就是原问题和子问题中会变化的变量。
本题中状态为数组最后一个值,影响是否需要改变的次数
-
确定「选择」,也就是导致「状态」产生变化的行为。
如果arr1[i]>=arr1[i−1]arr1[i]>=arr1[i - 1]arr1[i]>=arr1[i−1],那么不需要替换,dp[i]=dp[i−1]dp[i]=dp[i-1]dp[i]=dp[i−1]
如果arr1[i]<arr1[i−1]arr1[i]<arr1[i - 1]arr1[i]<arr1[i−1],那么我们需要将arr1[i−1]arr1[i-1]arr1[i−1]替换为为
arr2中小于arr1[i]arr1[i]arr1[i]的最大值arr2[j]arr2[j]arr2[j],然后在k∈[1,min(i−1,j)]k \in [1,min(i-1,j)]k∈[1,min(i−1,j)]的范围内枚举需要替换的个数,如果满足arr[i−k−1]<arr[j−k]arr[i-k-1] < arr[j-k]arr[i−k−1]<arr[j−k],那么将区间arr1[i−k+1,i−1]arr1[i-k+1,i-1]arr1[i−k+1,i−1]替换为arr2[j−k,j]arr2[j-k,j]arr2[j−k,j],dp[i]dp[i]dp[i]可以从dp[i−k−1]dp[i-k-1]dp[i−k−1]转移而来。因此状态转移方程为
dp[i+1]=mink=1min(i−1,j)(dp[i−k−1]+k) dp[i+1]=min_{k=1}^{min(i-1,j)}(dp[i-k-1]+k) dp[i+1]=mink=1min(i−1,j)(dp[i−k−1]+k)
-
-
-
实现
class Solution { public int makeArrayIncreasing(int[] arr1, int[] arr2) { Arrays.sort(arr2); int m = 0; for (int x : arr2) { if (m == 0 || x != arr2[m - 1]) { arr2[m++] = x; } } final int inf = 1 << 30; int[] arr = new int[arr1.length + 2]; arr[0] = -inf; arr[arr.length - 1] = inf; System.arraycopy(arr1, 0, arr, 1, arr1.length); int[] f = new int[arr.length]; Arrays.fill(f, inf); f[0] = 0; for (int i = 1; i < arr.length; ++i) { if (arr[i - 1] < arr[i]) { f[i] = f[i - 1]; } int j = search(arr2, arr[i], m); for (int k = 1; k <= Math.min(i - 1, j); ++k) { if (arr[i - k - 1] < arr2[j - k]) { f[i] = Math.min(f[i], f[i - k - 1] + k); } } } return f[arr.length - 1] >= inf ? -1 : f[arr.length - 1]; } private int search(int[] nums, int x, int n) { int l = 0, r = n; while (l < r) { int mid = (l + r) >> 1; if (nums[mid] >= x) { r = mid; } else { l = mid + 1; } } return l; } } 作者:ylb 链接:https://leetcode.cn/problems/make-array-strictly-increasing/solutions/2236262/python3javacgotypescript-yi-ti-yi-jie-do-j5ef/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。-
复杂度
- 时间复杂度:O(n(logm+min(n,m)))O(n(logm+min(n,m)))O(n(logm+min(n,m))),arr1和arr2数组长度分别为n和m
- 空间复杂度:O(n)O(n)O(n)
-
-
变形题:respect灵神


给定两个数组arr1和arr2,目标是使arr1严格递增,返回所需最小操作数。每步操作可将arr1的一个元素替换为arr2中的元素。文章提到的解决方案包括对arr2排序,使用二分查找找到合适的替换值,并应用动态规划来找到最小操作数。
16万+

被折叠的 条评论
为什么被折叠?



