求数组中恰好被n-1个元素整除的最小M:代码问题排查
问题需求
找到最小的数M,使其能被输入数组中恰好n-1个元素整除(n为数组长度),若不存在则返回-1。
- 样例1:数组
[2,3,5],答案为6,因6可被2和3整除(恰好2个元素,n-1=3-1=2)。 - 样例2:数组
[2,3,6],答案为-1,因无法找到符合条件的M(排除任意一个元素后的最小公倍数都会被第三个元素整除)。
用户代码的问题
当前代码逻辑是取数组前n-1个元素相乘并返回,存在以下核心问题:
- 未考虑最小公倍数,直接乘积不是最优解
比如数组[4,6,8],排除最后一个元素8后,剩余元素的最小公倍数是12(而非乘积24),12能被4和6整除,且不能被8整除,是符合要求的最小M。但用户代码返回24,不是正确的最小解。 - 未校验结果是否满足“恰好n-1个元素整除”的条件
以样例2[2,3,6]为例,用户代码返回2*3=6,但6能被数组中所有3个元素整除,不符合“恰好n-1个”的要求,此时应返回-1,但代码未做判断。 - 未遍历所有可能的排除情况
代码只排除了最后一个元素,忽略了排除数组中其他元素的情况。比如数组[3,4,6],排除4时最小公倍数是6(能被3、6整除,不能被4整除),这才是最小M,但用户代码返回3*4=12,错过正确解。 - 整数溢出风险
当数组元素较大或长度较长时,直接相乘会超出int类型的取值范围,导致结果错误。
正确解决思路
- 遍历数组中的每个元素,依次将其排除,计算剩余n-1个元素的最小公倍数(LCM)。
- 最小公倍数计算依赖最大公约数(GCD):
LCM(a,b) = a*b / GCD(a,b),多个元素的LCM可通过迭代计算两两的LCM得到。
- 最小公倍数计算依赖最大公约数(GCD):
- 对每个得到的LCM,检查它是否不能被被排除的元素整除,确保满足“恰好n-1个元素能整除”的条件。
- 收集所有符合条件的LCM,取其中的最小值;若没有符合条件的,返回-1。
修正后的代码示例
public int process(int[] arr) { int n = arr.length; if (n <= 1) { return -1; // 数组长度<=1时,n-1无意义 } int minM = Integer.MAX_VALUE; // 遍历每个要排除的元素 for (int excludeIdx = 0; excludeIdx < n; excludeIdx++) { int currentLCM = 1; boolean overflow = false; // 计算剩余元素的LCM for (int i = 0; i < n; i++) { if (i == excludeIdx) continue; try { currentLCM = lcm(currentLCM, arr[i]); } catch (ArithmeticException e) { overflow = true; break; } } if (overflow) continue; // 检查当前LCM是否不能被排除的元素整除 if (currentLCM % arr[excludeIdx] != 0) { if (currentLCM < minM) { minM = currentLCM; } } } return minM == Integer.MAX_VALUE ? -1 : minM; } // 计算最大公约数(GCD) private int gcd(int a, int b) { while (b != 0) { int temp = b; b = a % b; a = temp; } return a; } // 计算最小公倍数(LCM),处理溢出 private int lcm(int a, int b) { if (a == 0 || b == 0) return 0; int gcdVal = gcd(a, b); // 先除法再乘法避免溢出 return Math.multiplyExact(a / gcdVal, b); }
内容的提问来源于stack exchange,提问作者Learner
相关产品推荐
相关产品推荐

