网站首页 > 教程文章 正文
2025-05-23:数组的最大因子得分。用go语言,给定一个整数数组 nums。
定义“因子得分”为该数组中所有元素的最小公倍数(LCM)与最大公约数(GCD)相乘后的结果。
现在你最多可以移除数组中的一个元素,求在这种情况下,nums 的最大因子得分。
特别说明:
- o 如果数组只剩一个数字,则其因子得分等于该数字自身。
- o 如果数组为空,则因子得分为 0。
1 <= nums.length <= 100。
1 <= nums[i] <= 30。
输入: nums = [2,4,8,16]。
输出: 64。
解释:
移除数字 2 后,剩余元素的 GCD 为 4,LCM 为 16,因此最大因子得分为 4 * 16 = 64。
题目来自力扣3334。
解决思路
- 1. 理解因子得分:因子得分是数组的 LCM 和 GCD 的乘积。我们需要计算原始数组的因子得分,以及移除每一个可能的元素后的因子得分,然后取最大值。
- 2. 关键观察:
- o GCD:移除一个元素后,剩余数组的 GCD 是原数组 GCD(移除的元素可能不是 GCD 的约束)或更大的值。
- o LCM:移除一个元素后,剩余数组的 LCM 是原数组 LCM(移除的元素可能是 LCM 的关键)或更小的值。
- o 因此,我们需要高效计算移除每一个元素后的 GCD 和 LCM。
- 3. 预处理:
- o 后缀 GCD 数组 (sufGcd):sufGcd[i] 表示从 nums[i] 到 nums[n-1] 的 GCD。
- o 后缀 LCM 数组 (sufLcm):sufLcm[i] 表示从 nums[i] 到 nums[n-1] 的 LCM。
- o 这两个数组可以通过从后向前遍历 nums 来计算。
- 4. 计算原始因子得分:
- o 原始 GCD 是 sufGcd[0](即整个数组的 GCD)。
- o 原始 LCM 是 sufLcm[0](即整个数组的 LCM)。
- o 原始因子得分是 sufGcd[0] * sufLcm[0]。
- 5. 枚举移除每一个元素:
- o 对于移除 nums[i],剩余数组是 nums[0..i-1] 和 nums[i+1..n-1]。
- o 剩余数组的 GCD 是 gcd(prefixGcd, sufGcd[i+1]),其中 prefixGcd 是 nums[0..i-1] 的 GCD。
- o 剩余数组的 LCM 是 lcm(prefixLcm, sufLcm[i+1]),其中 prefixLcm 是 nums[0..i-1] 的 LCM。
- o 在遍历过程中维护 prefixGcd 和 prefixLcm:
- o 初始时 prefixGcd = 0(因为 gcd(0, x) = x),prefixLcm = 1(因为 lcm(1, x) = x)。
- o 遍历到 nums[i] 时,先计算移除 nums[i] 的因子得分,然后更新 prefixGcd 和 prefixLcm。
- 6. 取最大值:
- o 比较原始因子得分和所有移除一个元素后的因子得分,取最大值。
详细步骤
- 1. 初始化:
- o 计算数组长度 n。
- o 初始化 sufGcd 和 sufLcm 数组,大小为 n+1。
- o sufGcd[n] = 0(因为 gcd(0, x) = x),sufLcm[n] = 1(因为 lcm(1, x) = x)。
- 2. 填充后缀数组:
- o 从后向前遍历 nums:
- o sufGcd[i] = gcd(sufGcd[i+1], nums[i])。
- o sufLcm[i] = lcm(sufLcm[i+1], nums[i])。
- 3. 计算原始因子得分:
- o ans = sufGcd[0] * sufLcm[0]。
- 4. 枚举移除每一个元素:
- o 初始化 prefixGcd = 0,prefixLcm = 1。
- o 从左到右遍历 nums:
- o 对于 nums[i],计算移除后的 GCD 和 LCM:
- o currentGcd = gcd(prefixGcd, sufGcd[i+1])。
- o currentLcm = lcm(prefixLcm, sufLcm[i+1])。
- o currentScore = currentGcd * currentLcm。
- o 更新 ans = max(ans, currentScore)。
- o 更新 prefixGcd 和 prefixLcm:
- o prefixGcd = gcd(prefixGcd, nums[i])。
- o prefixLcm = lcm(prefixLcm, nums[i])。
- 5. 返回结果:
- o 返回 ans。
时间和空间复杂度
- o 时间复杂度:
- o 填充 sufGcd 和 sufLcm:O(n),因为每个元素处理一次,每次处理调用 gcd 和 lcm(可以视为 O(1) 因为数字很小)。
- o 枚举移除元素:O(n),同样每次处理调用 gcd 和 lcm。
- o 总时间复杂度:O(n)。
- o 空间复杂度:
- o sufGcd 和 sufLcm 数组:O(n)。
- o 其他变量:O(1)。
- o 总空间复杂度:O(n)。
Go完整代码如下:
package main
import (
"fmt"
"slices"
)
func maxScore(nums []int)int64 {
n := len(nums)
sufGcd := make([]int, n+1)
sufLcm := make([]int, n+1)
sufLcm[n] = 1
for i, x := range slices.Backward(nums) {
sufGcd[i] = gcd(sufGcd[i+1], x)
sufLcm[i] = lcm(sufLcm[i+1], x)
}
ans := sufGcd[0] * sufLcm[0] // 不移除元素
preGcd, preLcm := 0, 1
for i, x := range nums { // 枚举移除 nums[i]
ans = max(ans, gcd(preGcd, sufGcd[i+1])*lcm(preLcm, sufLcm[i+1]))
preGcd = gcd(preGcd, x)
preLcm = lcm(preLcm, x)
}
returnint64(ans)
}
func gcd(a, b int)int {
for a != 0 {
a, b = b%a, a
}
return b
}
func lcm(a, b int)int {
return a / gcd(a, b) * b
}
func main() {
nums := []int{2,4,8,16}
result := maxScore(nums)
fmt.Println(result)
}
Rust完整代码如下:
fn gcd(mut a: i64, mut b: i64) -> i64 {
while a != 0 {
let temp = a;
a = b % a;
b = temp;
}
b
}
fn lcm(a: i64, b: i64) -> i64 {
a / gcd(a, b) * b
}
fn max_score(nums: &[i64]) -> i64 {
let n = nums.len();
let mut suf_gcd = vec![0; n + 1];
let mut suf_lcm = vec![1; n + 1];
// 从后往前计算后缀的gcd和lcm
for i in (0..n).rev() {
suf_gcd[i] = gcd(suf_gcd[i + 1], nums[i]);
suf_lcm[i] = lcm(suf_lcm[i + 1], nums[i]);
}
// 不移除元素的情况
let mut ans = suf_gcd[0] * suf_lcm[0];
let mut pre_gcd = 0;
let mut pre_lcm = 1;
for i in 0..n {
// 移除 nums[i]
let curr = gcd(pre_gcd, suf_gcd[i + 1]) * lcm(pre_lcm, suf_lcm[i + 1]);
if curr > ans {
ans = curr;
}
pre_gcd = gcd(pre_gcd, nums[i]);
pre_lcm = lcm(pre_lcm, nums[i]);
}
ans
}
fn main() {
let nums = vec![2, 4, 8, 16];
let result = max_score(&nums);
println!("{}", result);
}
·
我们相信 Go 语言和算法为普通开发者提供了强有力的“面试利器”,并致力于分享全面的编程知识。在这里,您可以找到最新的 Go 语言教程、算法解析、提升面试竞争力的秘籍以及行业动态。
欢迎关注“福大大架构师每日一题”,让 Go 语言和算法助力您的职业发展
·
- 上一篇: 软件开发工程师笔试题系列之数组篇
- 下一篇: V32.VBA数组知识点76问(五)(数组 vba)
猜你喜欢
- 2025-06-12 二十、Java数组(java实现数组)
- 2025-06-12 十大经典排序算法-堆排序,计数排序,桶排序,基数排序
- 2025-06-12 3分钟短文 | PHP 根据值移除数组元素,哪个方法最简单?
- 2025-06-12 JAVA程序员常用的几个工具类(java程序员主要工作内容)
- 2025-06-12 C# 基础知识系列- 3 集合数组(c#集合排序)
- 2025-06-12 JUnit5学习之三:Assertions类(junit5 assert)
- 2025-06-12 打工人私藏的4个Excel函数秘籍,效率提升3.7%
- 2025-06-12 稀疏数组——前端电子表格中的应用实战
- 2025-06-12 最快清除数组空值?分享 1 段优质 JS 代码片段!
- 2025-06-12 excel这个复杂数组公式怎么读?(excel数组公式怎么复制)
- 最近发表
- 标签列表
-
- location.href (44)
- document.ready (36)
- git checkout -b (34)
- 跃点数 (35)
- 阿里云镜像地址 (33)
- qt qmessagebox (36)
- mybatis plus page (35)
- vue @scroll (38)
- 堆栈区别 (33)
- 什么是容器 (33)
- sha1 md5 (33)
- navicat导出数据 (34)
- 阿里云acp考试 (33)
- 阿里云 nacos (34)
- redhat官网下载镜像 (36)
- srs服务器 (33)
- pico开发者 (33)
- https的端口号 (34)
- vscode更改主题 (35)
- 阿里云资源池 (34)
- os.path.join (33)
- redis aof rdb 区别 (33)
- 302跳转 (33)
- http method (35)
- js array splice (33)