
2026-02-01:K 因数分解。用go语言,给定两个正整数 n 和 k,要把 n 表示为恰好 k 个正整数相乘的结果(因子允许重复)。在所有满足乘积为 n 的 k 元组中,挑出一组使其最大值与最小值之差最小。返回这样的一组数,输出顺序不限。
4 <= n <= 100000。
2 <= k <= 5。
k 严格小于 n 的正因数的总数。
输入:n = 44, k = 3。
输出:[2,2,11]。
解释:
分割方案 [1, 1, 44] 的差值为 43。
分割方案 [1, 2, 22] 的差值为 21。
分割方案 [1, 4, 11] 的差值为 10。
分割方案 [2, 2, 11] 的差值为 9。
因此,[2, 2, 11] 是最优分割方案,其差值最小,为 9。
题目来自力扣3669。
n 的所有因子,算法在程序开始时进行了一次性的预处理。divisors,它是一个长度为 mx (100,001) 的切片,每个元素 divisors[i] 是一个整数切片,用于存储数字 i 的所有正因子。i) 遍历从1到 mx-1 的所有数字,内层循环 (j) 枚举 i 的所有倍数(j = i, 2i, 3i, ...,且 j < mx)。对于每一个 j,将 i 加入到 divisors[j] 中,因为 i 是 j 的一个因子。n (n < mx),都可以通过 divisors[n] 立即获得其所有因子,且这些因子是按升序排列的(因为 i 是从小到大遍历的)。k 因子分解方案,并记录最优解。dfs(i, n) 是这个搜索过程的核心。i:表示当前已经确定了 i 个因子(即 path[0] 到 path[i-1] 已填充)。n:表示剩余需要被分解的数值,即 n = 初始n / (path[0] * path[1] * ... * path[i-1])。k-1个因子时(即i == k-1),最后一个因子必须是当前剩余的n值本身(因为所有因子相乘必须等于原始的n)。此时,当前分解方案path已经完整。计算该方案中最大值(即n)与最小值(即path[0])的差值。如果这个差值比之前记录的最小差值minDiff更小,则更新minDiff并将当前的path复制到结果ans 中。n 的所有因子 d(直接从预处理好的 divisors[n] 中获取)。d * d > n,说明 d 已经大于 sqrt(n),再枚举下去得到的因子会和之前枚举的因子对称(例如,对于 n=44,枚举完 d=2 和 d=22 是等价的),因此可以提前终止循环 (break)。i > 0),并且当前枚举的因子 d 与已确定的最小因子 path[0] 的差值已经大于或等于当前已知的最小差值 minDiff,那么即使继续分解下去,最终方案的差值也不可能小于 minDiff,因此也可以跳过后续更大的因子 (break)。d,需要满足非递减顺序的要求(即 i == 0 时第一个因子可以任意选,否则 d 必须大于等于前一个因子 path[i-1])。如果满足,则将 d 放入 path[i] 的位置,然后递归调用 dfs(i+1, n/d),继续分解剩下的数值。minDifference 函数是入口。它初始化用于记录最小差值的变量 minDiff 和一个长度为 k 的切片 path 用于记录当前搜索路径。dfs(0, n),从第0个因子开始,需要分解的数值为原始的 n。ans 中存储的就是找到的最优分解方案。O(mx) 次,内层循环运行 O(mx/i) 次(对于每个 i)。总操作数约为 mx * (1 + 1/2 + 1/3 + ... + 1/mx),这个求和是调和级数,其渐进复杂度为 O(mx log mx),其中 mx = 100,001。n的因数分解,方案数与其因子个数和k的值有关。由于k最大为5,且n <= 100,000,DFS的深度很浅(最多5层),但每一层分支较多。其时间复杂度可以近似看作O(d^k),其中d是n的因子个数。在n的范围内,一个数的因子个数d 通常不会非常大(几百量级),且剪枝策略有效减少了实际搜索空间。k 很小且剪枝有效,实际运行效率尚可。综合考虑,总的时间复杂度主要由DFS部分主导。divisors 数组需要 O(mx * d_avg) 的空间,其中 d_avg 是平均因子个数。对于 mx=100,001,这大约是几MB的量级。k (<=5),每一层递归的局部变量开销是常数。因此栈空间复杂度为 O(k)。path 和 ans 切片的大小均为 k,空间复杂度为 O(k)。divisors 数组决定,为 O(mx * d_avg)。该算法通过预处理构建因子表来加速因子枚举,并利用深度优先搜索结合有效的剪枝策略(因子大小限制、差值优化、非递减顺序)来寻找最优解。其优势在于能准确找到差值最小的分解方案,但由于问题本身的组合性质,在最坏情况下时间复杂度仍可能较高,好在题目约束 k 很小,使得算法在实践中可行。
.
package main
import (
"fmt"
"math"
"slices"
)
const mx = 100_001
var divisors [mx][]int
func init() {
// 预处理每个数的因子
for i := 1; i < mx; i++ {
for j := i; j < mx; j += i { // 枚举 i 的倍数 j
divisors[j] = append(divisors[j], i) // i 是 j 的因子
}
}
}
func minDifference(n, k int) (ans []int) {
minDiff := math.MaxInt
path := make([]int, k)
var dfs func(int, int)
dfs = func(i, n int) {
if i == k-1 {
// path[0] 最小,n 最大
if n-path[0] < minDiff {
minDiff = n - path[0]
path[i] = n
ans = slices.Clone(path)
}
return
}
for _, d := range divisors[n] { // 枚举 n 的因子 d
if d*d > n || i > 0 && d-path[0] >= minDiff {
break
}
if i == 0 || d >= path[i-1] {
path[i] = d // 直接覆盖,无需恢复现场
dfs(i+1, n/d)
}
}
}
dfs(0, n)
return
}
func main() {
n := 44
k := 3
result := minDifference(n, k)
fmt.Println(result)
}

.
# -*-coding:utf-8-*-
import math
import sys
from typing import List
MX = 100_001
# 预处理每个数的因子
divisors = [[] for _ in range(MX)]
for i in range(1, MX):
for j in range(i, MX, i): # 枚举 i 的倍数 j
divisors[j].append(i) # i 是 j 的因子
def min_difference(n: int, k: int) -> List[int]:
min_diff = float('inf')
path = [0] * k
ans = []
def dfs(i: int, current_n: int):
nonlocal min_diff, ans
if i == k - 1:
# path[0] 最小,current_n 最大
if current_n - path[0] < min_diff:
min_diff = current_n - path[0]
path[i] = current_n
ans = path.copy()
return
# 枚举 current_n 的因子 d
for d in divisors[current_n]:
if d * d > current_n or (i > 0 and d - path[0] >= min_diff):
break
if i == 0 or d >= path[i - 1]:
path[i] = d # 直接覆盖,无需恢复现场
dfs(i + 1, current_n // d)
dfs(0, n)
return ans
if __name__ == "__main__":
n = 44
k = 3
result = min_difference(n, k)
print(result)
.
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
#include <cmath>
using namespace std;
constint MX = 100001;
vector<int> divisors[MX];
// 预处理每个数的因子
void init() {
for (int i = 1; i < MX; i++) {
for (int j = i; j < MX; j += i) { // 枚举 i 的倍数 j
divisors[j].push_back(i); // i 是 j 的因子
}
}
}
void dfs(int i, int n, int k, int& minDiff, vector<int>& path, vector<int>& ans) {
if (i == k - 1) {
// path[0] 最小,n 最大
if (n - path[0] < minDiff) {
minDiff = n - path[0];
path[i] = n;
ans = path;
}
return;
}
for (int d : divisors[n]) { // 枚举 n 的因子 d
if (d * d > n || (i > 0 && d - path[0] >= minDiff)) {
break;
}
if (i == 0 || d >= path[i - 1]) {
path[i] = d; // 直接覆盖,无需恢复现场
dfs(i + 1, n / d, k, minDiff, path, ans);
}
}
}
vector<int> minDifference(int n, int k) {
vector<int> ans;
int minDiff = INT_MAX;
vector<int> path(k);
dfs(0, n, k, minDiff, path, ans);
return ans;
}
int main() {
init();
int n = 44;
int k = 3;
vector<int> result = minDifference(n, k);
for (int num : result) {
cout << num << " ";
}
cout << endl;
return0;
}
