网站首页 > 文章精选 正文
2025-06-16:最小数组和。用go语言,你有一个整数数组 nums 和三个整数 k、op1、op2。
你可以对数组进行以下两种操作:
- 1. 操作1:选择一个元素,将该元素除以2后向上取整。最多能执行 op1 次,每个元素最多执行一次此操作。
- 2. 操作2:选择一个元素,仅当它的值不少于 k 时,从该元素中减去 k。最多能执行 op2 次,每个元素最多执行一次此操作。
同一个元素可以同时执行这两种操作,但每种操作在该元素上只能使用一次。
你的目标是在进行任意次数操作后,使数组元素之和尽可能小。
请返回此情况下数组元素和的最小值。
1 <= nums.length <= 100。
0 <= nums[i] <= 100000。
0 <= k <= 100000。
0 <= op1, op2 <= nums.length。
输入: nums = [2,8,3,19,3], k = 3, op1 = 1, op2 = 1。
输出: 23。
解释:
对 nums[1] = 8 应用操作 2,使 nums[1] = 5。
对 nums[3] = 19 应用操作 1,使 nums[3] = 10。
结果数组变为 [2, 5, 3, 10, 3],在应用操作后具有最小可能和 23。
题目来自力扣3366。
解决思路
这个问题可以通过动态规划(DP)来解决。我们需要考虑对每个元素选择是否进行操作1或操作2,同时跟踪剩余的操作次数。
动态规划状态定义
定义 f[i][p][q] 表示处理前 i 个元素后,使用了 p 次操作1和 q 次操作2时,前 i 个元素的最小和。
状态转移
对于第 i 个元素 nums[i-1](假设数组从 0 开始),我们有以下选择:
- 1. 不进行任何操作:直接加上当前元素的值。
- 2. 进行操作1(如果 p > 0):将当前元素除以 2 并向上取整,然后加上。
- 3. 进行操作2(如果 q > 0 且当前元素 >= k):从当前元素中减去 k,然后加上。
- 4. 同时进行操作1和操作2(如果 p > 0 和 q > 0 且当前元素 >= k):先进行操作2(减去 k),然后进行操作1(除以 2 并向上取整),或者反之。这里需要计算哪种顺序更优。
对于同时进行操作1和操作2的情况,需要计算两种顺序的结果:
- o 先操作1后操作2:ceil((x + 1)/2) - k(如果 ceil((x + 1)/2) >= k)。
- o 先操作2后操作1:ceil((x - k + 1)/2)。
我们需要选择这两种顺序中较小的值。
初始化
f[0][p][q] = 0 表示处理前 0 个元素的和为 0。
填充DP表
对于每个元素 nums[i-1],遍历所有可能的 p 和 q,更新 f[i][p][q] 的值。
最终结果
最终结果是 f[n][op1][op2],即处理完所有 n 个元素后,使用了 op1 次操作1和 op2 次操作2的最小和。
具体步骤
- 1. 初始化DP表:创建一个三维数组 f,大小为 (n+1) x (op1+1) x (op2+1),初始值为 0。
- 2. 遍历每个元素:对于每个元素 nums[i-1],从 i = 1 到 n:
- o 对于所有可能的 p(从 0 到 op1)和 q(从 0 到 op2):
- o 计算不进行操作、操作1、操作2以及同时操作1和操作2的最小值。
- o 更新 f[i][p][q]。
- 3. 返回结果:f[n][op1][op2] 即为答案。
时间复杂度和空间复杂度
- o 时间复杂度:我们需要遍历 n 个元素,对于每个元素,遍历 op1 + 1 和 op2 + 1 的所有组合。因此,时间复杂度为 O(n * op1 * op2)。
- o 由于 op1 和 op2 最多为 n,因此最坏情况下为 O(n^3)。
- o 空间复杂度:DP表的大小为 (n+1) x (op1+1) x (op2+1),因此空间复杂度为 O(n * op1 * op2)。
- o 同样,最坏情况下为 O(n^3)。
总结
通过动态规划,我们能够系统地考虑所有可能的操作组合,并找到使数组和最小的操作序列。该方法的时间复杂度和空间复杂度均为 O(n^3),适用于题目给定的约束条件(n <= 100)。
Go完整代码如下:
.
package main
import (
"fmt"
)
func minArraySum(nums []int, k, op1, op2 int)int {
n := len(nums)
f := make([][][]int, n+1)
for i := range f {
f[i] = make([][]int, op1+1)
for j := range f[i] {
f[i][j] = make([]int, op2+1)
}
}
for i, x := range nums {
var y int
if (x+1)/2 >= k {
y = (x+1)/2 - k
} else {
y = (x - k + 1) / 2
}
for p := 0; p <= op1; p++ {
for q := 0; q <= op2; q++ {
res := f[i][p][q] + x
if p > 0 {
res = min(res, f[i][p-1][q]+(x+1)/2)
}
if q > 0 && x >= k {
res = min(res, f[i][p][q-1]+x-k)
if p > 0 {
res = min(res, f[i][p-1][q-1]+y)
}
}
f[i+1][p][q] = res
}
}
}
return f[n][op1][op2]
}
func main() {
nums := []int{2, 8, 3, 19, 3}
k := 3
op1 := 1
op2 := 1
fmt.Println(minArraySum(nums, k, op1, op2))
}
Python完整代码如下:
.
# -*-coding:utf-8-*-
def minArraySum(nums, k, op1, op2):
n = len(nums)
# 初始化三维DP数组,维度为 (n+1) x (op1+1) x (op2+1)
f = [[[float('inf')] * (op2+1) for _ in range(op1+1)] for _ in range(n+1)]
f[0][0][0] = 0
for i, x in enumerate(nums):
# 计算 y,基于题意处理
if (x + 1) // 2 >= k:
y = (x + 1) // 2 - k
else:
y = (x - k + 1) // 2
for p in range(op1+1):
for q in range(op2+1):
# 不操作当前元素
res = f[i][p][q] + x
# 操作1,除以2向上取整
if p > 0:
res = min(res, f[i][p-1][q] + (x + 1) // 2)
# 操作2,减去k(条件:x >= k)
if q > 0 and x >= k:
res = min(res, f[i][p][q-1] + x - k)
# 操作1和操作2都做
if p > 0:
res = min(res, f[i][p-1][q-1] + y)
f[i+1][p][q] = res
return f[n][op1][op2]
if __name__ == '__main__':
nums = [2, 8, 3, 19, 3]
k = 3
op1 = 1
op2 = 1
print(minArraySum(nums, k, op1, op2))
·
我们相信Go语言和算法为普通开发者提供了困境的“面试利器”,并致力于分享全面的编程知识。在这里,您可以找到最新的Go语言教程、算法解析、提升面试竞争力的秘籍以及行业动态。
欢迎关注“福大规模架构师每日一题”,让 Go 语言和算法助力您的职业发展
·
猜你喜欢
- 2025-07-14 Go并发编程之WaitGroup(go语言 并发)
- 2025-07-14 golang企业微信告警(企业微信告警推送)
- 2025-07-14 2.8 Go语言中的for循环,break和continue
- 2025-07-14 Go语言Context包:最常用包之一的使用指南
- 2025-07-14 Go语言零到一:动态数组——切片(go语言的切片)
- 2025-07-14 2025-06-26:转换数组。用go语言,给你一个整数数组 nums,它被视
- 2025-07-14 go sync.Pool简介(go system)
- 2025-07-14 2025-07-13:统计特殊子序列的数目。用go语言,给定一个只包含正
- 2025-07-14 Go语言数据库编程:GORM 的基本使用
- 2025-07-14 2025-06-28:长度可被 K 整除的子数组的最大元素和。用go语言,给
- 最近发表
- 标签列表
-
- newcoder (56)
- 字符串的长度是指 (45)
- drawcontours()参数说明 (60)
- unsignedshortint (59)
- postman并发请求 (47)
- python列表删除 (50)
- 左程云什么水平 (56)
- 编程题 (64)
- postgresql默认端口 (66)
- 数据库的概念模型独立于 (48)
- 产生系统死锁的原因可能是由于 (51)
- 数据库中只存放视图的 (62)
- 在vi中退出不保存的命令是 (53)
- 哪个命令可以将普通用户转换成超级用户 (49)
- noscript标签的作用 (48)
- 联合利华网申 (49)
- swagger和postman (46)
- 结构化程序设计主要强调 (53)
- 172.1 (57)
- apipostwebsocket (47)
- 唯品会后台 (61)
- 简历助手 (56)
- offshow (61)
- mysql数据库面试题 (57)
- fmt.println (52)