【算法】Make Array Strictly Increasing 使数组严格递增

文章介绍了如何解决使数组arr1严格递增的最小操作数问题,通过对两个给定数组arr1和arr2进行操作,分析了从右向左的策略,并提出了使用深度优先搜索(DFS)或动态规划(DP)的方法。文章提供了详细的递归思路和边界条件,以及相应的Java代码实现,代码中使用了排序、二分查找和动态规划数组来优化时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Make Array Strictly Increasing 使数组严格递增

问题描述:

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

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

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

arr1.length,arr2.length 范围[1,2000]

arr1[i], arr2[i] 范围[0,10^9]

分析

要计算将arr1数组最终达到严格递增操作的最少此时,而一次操作,就是从arr2中选一个元素赋值到arr1中,因为要求最终是严格递增的,所以不会允许arr2中的一个元素使用2次以上。
因为要求操作最少,最理想的情况下就是0操作,即原始的数组就是满足严格递增的。
对于长度n的数组来说,对具体的i,arr[i]进行操作是一个问题,将arr[i] 更新成为x,y,z,又是一个问题。
每一个a[i]都有可能更新,但是更新的策略就很关键。
如果是从左到右,出现a[i]>=a[i+1],具体更新哪一个,如果可以更新a[i]变小,或者a[i+1]变大,都可以满足。正向的思路不流畅,无法找到共性。
如果从右向左,对于a[i]来说,可以选择更新成为a2中最大的,或者不更新,那么对于a[i-1],就有限制,限制来源于此时的a[i],记此时的a[i]为 tar。
情况 1
如果a[i-1]>=tar,说明要满足题意a[i-1]就必须更新为a’[i-1]<tar,而且要尽可能的靠近tar,同时在a2中寻找是否存在这样的元素,如果存在那么就可以更新,否则这个序列就不可能存在。
情况 2
如果a[i-1]<tar,说明在不修改a[i-1]的情况下,就可以满足题意,可以去看0~i-2。
当然也可以将a[i-1],修改为小于tar的最大元素,

所以可以发现定义问题就是 对a[i] 是否选择修改,而且要满足a[i]<tar的情况下的最小操作数。
用dfs(int ind,int tar),ind表示当0~ind为严格递增,&&a[ind]<tar时 的最小操作数。
不修改a[ind] 【当然必须满足a[ind]<tar】,int res1 =dfs(ind-1,a[ind])
修改a[ind],
可以找到最大的 a2[x] <tar,int res2 = dfs(ind-1,a2[x])+1
找不到满足条件的a2[x]<tar,int res2 = INTMAX.
所以当无法找到合适的序列时,dfs应该返回一个较大的值INTMAX。
那么 对于 dfs()来说, 最终返回的应该是min(res1,res2);
递归的边界就是 当ind<0时,返回0.

在上面递归理论上也可以做出从左到右的递推.
但是如果按照递归的思路,f[i][j],j作为第i个位置的取值维度就会比较分散。
就需要做一些调整,定义f[i][j],表示前i个元素,恰好完成j次替换时达到有序序列时的尾部元素可以取到的最小值。
用极大值INTMAX初始化f,最终的结果就是遍历f[n][0~~j],取j的最小值。
因为替换也是有上限的,上边界就是min(a1,a2),同时下边界就是0.如果存在这样的序列,j一定是属于[0,min(a1,a2)].
从左到右的思路,对于a1[i],也分2个情况
1 保持不变,如果a1[i-1]<a1[i],这个选择是允许的,否则这个序列就不可能存在。
2 修改a1[i],修改后的tar值范围(a1[i-1],a1[i+1]),为了保证后续的存在,tar应该从a2中选择属于这个范围内的最小元素。
即f[i][j] = min(a1[i]), && a1[i]>f[i-1][j],//保留
f[i][j] = min(a2[k]), && a2[k]>f[i-1][j-1],//修改

代码

class Solution {
    static final int INF = 0x3f3f3f3f;

    public int makeArrayIncreasing(int[] arr1, int[] arr2) {
        Arrays.sort(arr2);
        List<Integer> list = new ArrayList<Integer>();
        int prev = -1;
        for (int num : arr2) {
            if (num != prev) {
                list.add(num);
                prev = num;
            }
        }
        int n = arr1.length;
        int m = list.size();
        int[][] dp = new int[n + 1][Math.min(m, n) + 1];
        for (int i = 0; i <= n; i++) {
            Arrays.fill(dp[i], INF);
        }
        dp[0][0] = -1;
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j <= Math.min(i, m); j++) {
                /* 如果当前元素大于序列的最后一个元素 */
                if (arr1[i - 1] > dp[i - 1][j]) {
                    dp[i][j] = arr1[i - 1];
                }
                if (j > 0 && dp[i - 1][j - 1] != INF) {
                    /* 查找严格大于 dp[i - 1][j - 1] 的最小元素 */
                    int idx = binarySearch(list, j - 1, dp[i - 1][j - 1]);
                    if (idx != list.size()) {
                        dp[i][j] = Math.min(dp[i][j], list.get(idx));
                    }
                }
                if (i == n && dp[i][j] != INF) {
                    return j;
                }
            }
        }
        return -1;
    }

    public int binarySearch(List<Integer> list, int low, int target) {
        int high = list.size();
        while (low < high) {
            int mid = low + (high - low) / 2;
            if (list.get(mid) > target) {
                high = mid;
            } else {
                low = mid + 1;
            }
        }
        return low;
    }
}
 

时间复杂度 O( N ∗ m i n ( M , N ) ∗ L o g M N*min(M,N)*LogM Nmin(M,N)LogM)
空间复杂度: O( N ∗ m i n ( M , N ) N*min(M,N) Nmin(M,N))

Tag

Array Binary Dynamic Programming

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Eric.Cui

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值