2023-12-09:用go语言,给你两个整数数组 arr1 和 arr2,

返回使 arr1 严格递增所需要的最小「操作」数(可能为 0)。

每一步「操作」中,你可以分别从 arr1 和 arr2 中各选出一个索引,

分别为 i 和 j,0 <= i < arr1.length 和 0 <= j < arr2.length,

然后进行赋值运算 arr1[i] = arr2[j]。如果无法让 arr1 严格递增,请返回 -1。

输入:arr1 = [1,5,3,6,7], arr2 = [4,3,1]。

输出:2。

答案2023-12-09:

灵捷3.5

大体过程如下:

算法1(makeArrayIncreasing1):

1.对arr2进行排序并去除重复元素,生成新的数组help,并统计cnt为help的长度。

2.通过递归函数process1来计算从arr1的索引i开始到结尾的最小操作数。初始时,i为-1。

3.在process1中,通过二分查找函数find,在arr2中找到第一个大于cur的元素的索引f。

4.使用循环遍历arr1中从i+1到末尾的元素。

  • 若当前元素大于cur,则说明可以选择该元素,继续递归调用process1,并将操作数times加1。

  • 若f不等于-1且小于arr2的长度,更新cur为arr2[f],同时f加1,times加1。

  • 若f等于-1或大于等于arr2的长度,跳出循环。

5.返回递归调用的结果ans,即最小操作数。

算法2(makeArrayIncreasing2):

1.对arr2进行排序并去除重复元素,生成新的数组help,并统计cnt为help的长度。

2.创建dp数组,初始值为-1。

3.通过递归函数process2来计算从arr1的索引i开始到结尾的最小操作数。同时,使用dp数组记录已计算过的结果,以便后续查询。

4.在process2中,若dp[i+1]不等于-1,直接返回dp[i+1]。

5.剩下的过程与makeArrayIncreasing1基本相同,只是将递归调用替换为对dp数组的查询和更新。

6.返回递归调用的结果ans,同时将其保存到dp[i+1]中。

算法3(makeArrayIncreasing3):

1.对arr2进行排序并去除重复元素,生成新的数组arr2,并统计m为arr2的长度。

2.创建dp数组,长度为n+2,并初始化为最大整数。

3.从arr1末尾向前遍历,使用循环计算从索引i开始到结尾的最小操作数。

  • 初始化cur为arr1[i],f为在arr2中找到第一个大于cur的元素的索引。

  • 初始化dp[i+1]为最大整数,times为0。

  • 使用循环遍历arr1中从i+1到末尾的元素,操作步骤与makeArrayIncreasing1和makeArrayIncreasing2相似。

  • 若dp[j+1]不等于最大整数,更新dp[i+1]为times+dp[j+1]与dp[i+1]中的较小值。

  • 若f不等于-1且小于m,更新cur为arr2[f],同时f加1,times加1。

  • 若f等于-1或大于等于m,跳出循环。

4.若dp[0]等于最大整数,返回-1;否则返回dp[0]作为最小操作数。

时间复杂度分析:

  • 算法1和算法2的时间复杂度为O(n * m),其中n和m分别为arr1和arr2的长度,因为每个元素都需要遍历一次。

  • 算法3的时间复杂度为O(n * m + m * log(m)),其中m为arr2的长度,因为要对arr2进行排序并进行二分查找。

额外空间复杂度分析:

  • 算法1和算法2的额外空间复杂度为O(m),用于存储去重后的arr2。

  • 算法3的额外空间复杂度为O(m),用于存储去重后的arr2,并且使用了一个大小为n+2的dp数组来记录中间结果。

go完整代码如下:

package main

import (
"fmt"
"math"
"sort"
) func makeArrayIncreasing1(arr1 []int, arr2 []int) int {
sort.Ints(arr2)
cnt := 1
for i := 1; i < len(arr2); i++ {
if arr2[i] != arr2[i-1] {
cnt++
}
}
help := make([]int, cnt)
help[0] = arr2[0]
for i, j := 1, 1; i < len(arr2); i++ {
if arr2[i] != arr2[i-1] {
help[j] = arr2[i]
j++
}
}
ans := process1(arr1, help, -1)
if ans == math.MaxInt64 {
return -1
}
return ans
} func process1(arr1 []int, arr2 []int, i int) int {
if i == len(arr1) {
return 0
} else {
cur := 0
if i == -1 {
cur = math.MinInt64
} else {
cur = arr1[i]
}
f := find(arr2, cur)
ans := math.MaxInt64
times := 0
for j := i + 1; j <= len(arr1); j++ {
if j == len(arr1) || cur < arr1[j] {
next := process1(arr1, arr2, j)
if next != math.MaxInt64 {
ans = min(ans, times+next)
}
}
if f != -1 && f < len(arr2) {
cur = arr2[f]
f++
times++
} else {
break
}
}
return ans
}
} func find(arr2 []int, num int) int {
l := 0
r := len(arr2) - 1
ans := -1
for l <= r {
m := (l + r) / 2
if arr2[m] > num {
ans = m
r = m - 1
} else {
l = m + 1
}
}
return ans
} func min(a, b int) int {
if a < b {
return a
}
return b
} func makeArrayIncreasing2(arr1 []int, arr2 []int) int {
sort.Ints(arr2)
cnt := 1
for i := 1; i < len(arr2); i++ {
if arr2[i] != arr2[i-1] {
cnt++
}
}
help := make([]int, cnt)
help[0] = arr2[0]
for i, j := 1, 1; i < len(arr2); i++ {
if arr2[i] != arr2[i-1] {
help[j] = arr2[i]
j++
}
}
dp := make([]int, len(arr1)+1)
for i := range dp {
dp[i] = -1
}
ans := process2(arr1, help, -1, dp)
if ans == math.MaxInt64 {
return -1
}
return ans
} func process2(arr1 []int, arr2 []int, i int, dp []int) int {
if i == len(arr1) {
return 0
} else {
if dp[i+1] != -1 {
return dp[i+1]
}
cur := 0
if i == -1 {
cur = math.MinInt64
} else {
cur = arr1[i]
}
f := find(arr2, cur)
ans := math.MaxInt64
times := 0
for j := i + 1; j <= len(arr1); j++ {
if j == len(arr1) || cur < arr1[j] {
next := process2(arr1, arr2, j, dp)
if next != math.MaxInt64 {
ans = min(ans, times+next)
}
}
if f != -1 && f < len(arr2) {
cur = arr2[f]
f++
times++
} else {
break
}
}
dp[i+1] = ans
return ans
}
} func makeArrayIncreasing3(arr1 []int, arr2 []int) int {
sort.Ints(arr2)
m := 1
for i := 1; i < len(arr2); i++ {
if arr2[i] != arr2[m-1] {
arr2[m] = arr2[i]
m++
}
}
n := len(arr1)
dp := make([]int, n+2)
for i := n - 1; i >= -1; i-- {
cur := 0
if i == -1 {
cur = math.MinInt64
} else {
cur = arr1[i]
}
f := find3(arr2, m, cur)
dp[i+1] = math.MaxInt64
times := 0
for j := i + 1; j <= n; j++ {
if j == n || cur < arr1[j] {
if dp[j+1] != math.MaxInt64 {
dp[i+1] = min(dp[i+1], times+dp[j+1])
}
}
if f != -1 && f < m {
cur = arr2[f]
f++
times++
} else {
break
}
}
}
if dp[0] == int(^uint(0)>>1) {
return -1
}
return dp[0]
} func find3(arr2 []int, size int, num int) int {
l := 0
r := size - 1
ans := -1
for l <= r {
m := (l + r) / 2
if arr2[m] > num {
ans = m
r = m - 1
} else {
l = m + 1
}
}
return ans
} func main() {
if true {
arr1 := []int{1, 5, 3, 6, 7}
arr2 := []int{4, 3, 1}
fmt.Println(makeArrayIncreasing1(arr1, arr2))
}
if true {
arr1 := []int{1, 5, 3, 6, 7}
arr2 := []int{4, 3, 1}
fmt.Println(makeArrayIncreasing2(arr1, arr2))
}
if true {
arr1 := []int{1, 5, 3, 6, 7}
arr2 := []int{4, 3, 1}
fmt.Println(makeArrayIncreasing3(arr1, arr2))
}
}

2023-12-09:用go语言,给你两个整数数组 arr1 和 arr2, 返回使 arr1 严格递增所需要的最小「操作」数(可能为 0)。 每一步「操作」中,你可以分别从 arr1 和 arr2的更多相关文章

  1. c语言经典算法——查找一个整数数组中第二大数

    题目: 实现一个函数,查找一个整数数组中第二大数. 算法思想: 设置两个变量max1和max2,用来保存最大数和第二大数,然后将数组剩余的数依次与这两个数比较,如果这个数a比max1大,则先将max1 ...

  2. Leecode刷题之旅-C语言/python-88合并两个有序数组

    /* * @lc app=leetcode.cn id=88 lang=c * * [88] 合并两个有序数组 * * https://leetcode-cn.com/problems/merge-s ...

  3. 12天学好C语言——记录我的C语言学习之路(Day 12)

    12天学好C语言--记录我的C语言学习之路 Day 12: 进入最后一天的学习,用这样一个程序来综合考量指针和字符串的关系,写完这个程序,你对字符串和指针的理解应该就不错了. //输入一个字符串,内有 ...

  4. 12天学好C语言——记录我的C语言学习之路(Day 11)

    12天学好C语言--记录我的C语言学习之路 Day 11: 因为指针部分比较的难,所以我们花费的时间也是最长的,希望大家耐的住性子,多多理解,多多打代码.好了,废话不多说,来看第11天的学习. //编 ...

  5. 12天学好C语言——记录我的C语言学习之路(Day 9)

    12天学好C语言--记录我的C语言学习之路 Day 9: 函数部分告一段落,但是我们并不是把函数完全放下,因为函数无处不在,我们今后的程序仍然会大量运用到函数 //转入指针部分的学习,了解指针是什么 ...

  6. 12天学好C语言——记录我的C语言学习之路(Day 8)

    12天学好C语言--记录我的C语言学习之路 Day 8: 从今天开始,我们获得了C语言中很有力的一个工具,那就是函数.函数的魅力不仅于此,一个程序到最后都是由众多函数组成的,我们一定要用好函数,用熟练 ...

  7. 12天学好C语言——记录我的C语言学习之路(Day 7)

    12天学好C语言--记录我的C语言学习之路 Day 7: 昨天进行了一天的数组学习,今天大家可以先写几个昨天的程序热热身,回顾回顾,然后今天第一个新程序也是关于数组的,比较难,准备好就开始啦! //输 ...

  8. 12天学好C语言——记录我的C语言学习之路(Day 3)

    12天学好C语言--记录我的C语言学习之路 Day 3: 不知不觉到了第三天的学习,我们前两天学习的东西很杂乱,各个方面都有学习.我觉得这不是不系统,也不是学的不扎实,这种学习对于初学者而言我认为是很 ...

  9. 12天学好C语言——记录我的C语言学习之路(Day 1)

    12天学好C语言--记录我的C语言学习之路 Day 1: 刚刚入门C语言,那么肯定要先把什么是C语言和大家讲清楚,那么大家看下面一段程序(program  1.1): /*//program 1.1 ...

  10. 12天学好C语言——记录我的C语言学习之路(Day 10)

    12天学好C语言--记录我的C语言学习之路 Day 10: 接着昨天的指针部分学习,有这么一个题目: //还是四个学生,四门成绩,只要有学生一门功课没及格就输出这个学生的所有成绩 /*//progra ...

随机推荐

  1. IDApython练习1-脚本去花

    IDApython练习1-脚本去花 这里主要是练习IDApython脚本去花 1 这里 jz跳转条件是zf=1, jnz跳转条件是zf=0, 但是zf就2种可能,所以无论如何都会跳转到loc_411D ...

  2. 图解 LeetCode 算法汇总——链表

    本文首发公众号:小码A梦 一般数据主要存储的形式主要有两种,一种是数组,一种是链表.数组是用来存储固定大小的同类型元素,存储在内存中是一片连续的空间.而链表就不同于数组.链表中的元素不是存储在内存中可 ...

  3. 分拣平台API安全治理实战 | 京东物流技术团队

    导读 本文主要基于京东物流的分拣业务平台在生产环境遇到的一些安全类问题,进行定位并采取合适的解决方案进行安全治理,引出对行业内不同业务领域.不同类型系统的安全治理方案的探究,最后笔者也基于自己在金融领 ...

  4. mpi转以太网连接300PLC无需编程与1200PLC数据交换

    300PLC转以太网无需编程300PLC通过 NetDevice与1200PLC数据交换 应用概述: 兴达易控MPI转以太网模块MPI-ETH-XD1.0PLUS 通讯模块实现PLC无需编程通过简单的 ...

  5. strimzi实战之三:prometheus+grafana监控(按官方文档搞不定监控?不妨看看本文,已经踩过坑了)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 由于整个系列的实战都涉及到消息生产和消费,所 ...

  6. 【知识杂谈#2】如何查看Linux的(本地与公网)IP地址与SSH服务的端口号

    1. 本地Ip地址查看 使用查看linux主机是否有net-tools dpkg -l net-tools 显示以下代码就说明已安装成功 ||/ Name Version Architecture D ...

  7. C#使用iKvm黑科技无缝接入JVM生态

    前言 时间过得飞快,一转眼国庆假期也要过去了,再不更新博客就太咸鱼了-- 最近在开发AIHub的时候想找个C#能用的命名实体识别库,但一直没找到,AI生态方面C#确实不太丰富,这块还是得Python, ...

  8. 聊聊JDK19特性之虚拟线程

    1.前言 在读<深入理解JVM虚拟机>这本书前两章的时候整理了JDK从1.0到最新版本发展史,其中记录了JDK这么多年来演进过程中的一些趣闻及引人注目的一些特性,在调研JDK19新增特性的 ...

  9. 高可用mongodb集群(分片+副本):用户权限配置

    目录 ■ 创建副本集认证的key文件 ■ 修改配置文件指定keyfile ■ 重新启动节点 ■ 创建帐号和认证 ■ 用管理员帐号可查看整体的分片情况 ■ 用普通帐号访问数据 ■ 客户端连接多个mong ...

  10. K8S太庞大,这款PasteSpider绝对适合你!一款轻量级容器部署管理工具

    PasteSpider采用.netcore编写,运行于linux服务器的docker/podman里面,涉及的技术或者工具有podman/docker,registry,nginx,top,ssh,g ...