【每日一题Day183】LC1187使数组严格递增 | dp

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

使数组严格递增【LC1187】

给你两个整数数组 arr1arr2,返回使 arr1 严格递增所需要的最小「操作」数(可能为 0)。

每一步「操作」中,你可以分别从 arr1arr2 中各选出一个索引,分别为 ij0 <= i < arr1.length0 <= j < arr2.length,然后进行赋值运算 arr1[i] = arr2[j]

如果无法让 arr1 严格递增,请返回 -1

很难呀 需要消化(为什么有时候感觉自己很聪明 有时候感觉很笨笨)

  • 思路

    • 首先很容易想到的是,将arr2排序,如果 a r r 1 [ i ] < = a r r 1 [ i − 1 ] arr1[i]<=arr1[i - 1] arr1[i]<=arr1[i1],为了满足递增我们应该将 a r r 1 [ i − 1 ] arr1[i-1] arr1[i1]替换为arr2中小于 a r r 1 [ i ] arr1[i] arr1[i]的最大值【二分查找】(我就想到这里,没有想到还要用dp)

    • 然后,使数组arr1 i i i个元素严格递增需要的最小「操作」数可以由之前的状态转移得到【替换或者不替换,替换的值取决于下一个元素的大小(本题限制因素)】,因此可以定义状态 d p [ i ] dp[i] dp[i]为将arr1[0:i]转化为严格递增数组,并且 a r r [ i ] arr[i] arr[i]不做替换的最小操作数

      • 确定 base case,初始状态的值: d p [ 0 ] = 0 , d p [ i ] = ∞ dp[0]=0,dp[i]= \infty dp[0]=0dp[i]=

      • 确定「状态」,也就是原问题和子问题中会变化的变量

        本题中状态为数组最后一个值,影响是否需要改变的次数

      • 确定「选择」,也就是导致「状态」产生变化的行为

        如果 a r r 1 [ i ] > = a r r 1 [ i − 1 ] arr1[i]>=arr1[i - 1] arr1[i]>=arr1[i1],那么不需要替换, d p [ i ] = d p [ i − 1 ] dp[i]=dp[i-1] dp[i]=dp[i1]

        如果 a r r 1 [ i ] < a r r 1 [ i − 1 ] arr1[i]<arr1[i - 1] arr1[i]<arr1[i1],那么我们需要将 a r r 1 [ i − 1 ] arr1[i-1] arr1[i1]替换为为arr2中小于 a r r 1 [ i ] arr1[i] arr1[i]的最大值 a r r 2 [ j ] arr2[j] arr2[j],然后在 k ∈ [ 1 , m i n ( i − 1 , j ) ] k \in [1,min(i-1,j)] k[1,min(i1,j)]的范围内枚举需要替换的个数,如果满足 a r r [ i − k − 1 ] < a r r [ j − k ] arr[i-k-1] < arr[j-k] arr[ik1]<arr[jk],那么将区间 a r r 1 [ i − k + 1 , i − 1 ] arr1[i-k+1,i-1] arr1[ik+1,i1]替换为 a r r 2 [ j − k , j ] arr2[j-k,j] arr2[jk,j] d p [ i ] dp[i] dp[i]可以从 d p [ i − k − 1 ] dp[i-k-1] dp[ik1]转移而来。

        因此状态转移方程为
        d p [ i + 1 ] = m i n k = 1 m i n ( i − 1 , j ) ( d p [ i − k − 1 ] + k ) dp[i+1]=min_{k=1}^{min(i-1,j)}(dp[i-k-1]+k) dp[i+1]=mink=1min(i1,j)(dp[ik1]+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 ( l o g m + m i n ( 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灵神

    image-20230420160902723

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值