使数组严格递增

news/2024/10/21 20:32:03/

题目描述

给你两个整数数组 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

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/make-array-strictly-increasing
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

分析

本题难点在于如何定义动态规划状态以及状态转移方程
以往我们定义dp数组的值都是子问题的答案
但是在这里我们定义dp[i][j]表示arr1前i个元素经过j次变换后生成严格递增序列的末尾元素的最小值
而答案是dp[arr1.length][j]存在的时候j的最小值。

对于arr1中的每一个数arr1[i]我们都有两种选择:替换和不替换
1、不替换的前提是arr1[i]>dp[i-1][j],即在已经构建好的前i-1个元素递增序列尾加上当前元素仍是递增序列,此时dp[i][j]=arr1[i-1]
2、如果替换,则就要找到arr2中能够替换的最小值,也就是在arr2中>dp[i-1][j-1]的最小的值。替换后dp[i][j]=arr2[k]
最终取更小的那个赋值给dp[i][j]。

j的取值范围是0~min(i,arr2中可以用来替换的元素总个数),arr1的前i个元素最多可以被替换i次,最多能被arr2中不重复的元素来替换。

代码

class Solution {final int MaxV=Integer.MAX_VALUE;public int makeArrayIncreasing(int[] arr1, int[] arr2) {int m=arr1.length;Arrays.sort(arr2);List<Integer> list=new ArrayList<>();int f=-1;for(int x:arr2){if(x!=f){list.add(x);f=x;}}int n=list.size();int[][] dp=new int[m+1][Math.min(m,n)+1];for(int[] y:dp){Arrays.fill(y,MaxV);}dp[0][0]=-1;for(int i=1;i<m+1;i++){for(int j=0;j<=Math.min(i,n);j++){//不替换if(arr1[i-1]>dp[i-1][j]){dp[i][j]=arr1[i-1];}//进行替换,dp[i][j]=MaxV表示不存在这样的替换if(j>0 && dp[i-1][j-1]!=MaxV){int k=binarySearch(list,j-1,dp[i-1][j-1]);if(k!=n){//k=n,表示list中的最后一个元素(也就是最大值)都比dp[i-1][j-1]小,说明无法通过替换构成递增序列dp[i][j]=Math.min(dp[i][j],list.get(k));}}if(i==m && dp[i][j]!=MaxV){return j;}}}return -1;}//二分查找寻找target的插入位置也就是用来替换的元素索引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;}
}

http://www.ppmy.cn/news/49167.html

相关文章

【Leetcode -21.合并两个有序链表 -83.删除排序链表中的重复元素】

Leetcode Leetcode-21.合并两个有序链表Leetcode-83.删除排序链表中的重复元素 Leetcode-21.合并两个有序链表 题目&#xff1a;将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 […

诊断报文和通讯报文有什么区别?

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…

聚焦商会 | 活动彰显一个商会的战斗力与影响力

4月13日&#xff0c;北京厦航嘉年华酒店。 一个普通的日子&#xff0c;对北京茶业企业商会来说却是值得纪念的一天&#xff0c;可以浓笔重墨书写的一天。 一天成功举办了三场活动&#xff0c;得到社会各界的支持与肯定。 北京茶业企业商会是如何做到的&#xff1f;经过与商会领…

Vue(数据绑定、el和data多种写法、理解MVVM、数据代理)

一、数据绑定 1. vue中有两种数据绑定&#xff08;通过开发者工具进行查看&#xff09; 1. 单项绑定&#xff08;v-bind&#xff09;数据只能从data流向页面 在输入框中中输入vue实例中的数据没有变化 2. 双向绑定&#xff08;v-model&#xff09;数据能从data流向页面&#x…

Linux应用编程(进程)

一、进程与程序 注册进程终止处理函数 atexit() #include <stdlib.h> int atexit(void (*function)(void));使用该函数需要包含头文件<stdlib.h>。 函数参数和返回值含义如下&#xff1a; function&#xff1a;函数指针&#xff0c;指向注册的函数&#xff0c;此…

Shell 脚本编程

1. shell 概述 &#x1f95e; shell 是一个命令行解释器&#xff0c;它能接受应用程序、用户 的命令&#xff0c;然后调用操作系统内核。 ⭐ 还是一门 功能强大的编程语言&#xff0c;易编写、易调试、灵活性强。 2. shell入门 &#xff08;1&#xff09;脚本格式 &#x1f…

8款数据迁移工具选型,主流且实用

前言&#xff1a;ETL(是Extract-Transform-Load的缩写&#xff0c;即数据抽取、转换、装载的过程)&#xff0c;对于企业应用来说&#xff0c;我们经常会遇到各种数据的处理、转换、迁移的场景。今天特地给大家汇总了一些目前市面上比较常用的ETL数据迁移工具&#xff0c;希望对…

展会邀请 | 虹科诚邀您4月26-28日前来参观成都国际工业博览会

HONGKE NEWS 2023 成都国际工业博览会精准聚焦中国智能制造&#xff0c;将通过展示自动化和工业机器人技术、新一代信息技术、金属加工、节能与工业配套、新材料等全行业最新技术和解决方案&#xff0c;完美呈现智能工业产业链中的创新技术及产品的有效融合。 2023年4月26日-…