eg:
n=16
16=1+1+1+..+1 16 个
16=4+4+4+4 4个
16=16 1个
所以最少为一个
n=8;
8=1+1+..+1 8个
8=4+4 2个
最少为两个
首先想到了用树形dp
那么如何构造呢?
因子追加的思路
eg: n=8
当只有一个因子1*1的时候 从0-8每个数需要的最小因子个数分别为 0, 1,2,3,4,5,6,7,8
当添加因子2*2的时候 从0-8每个数需要的最小因子个数分别为 0,1,2,3,1,2,3,4,2
我们发现在计算添加因子2*2时 每个数(n)的最小因子数等于 n/(2*2)+上一个在n%(2*2)位置的数。
所以很容易想到使用二维dp[i][j]
dp结构 为 dp[M][N]
N=n+1;
M=n的开放取整再加一
M表示因子的开方 1,2,3,4...
N表示当前开放的因子个数从 1-n所需要的最少因子个数
dp[1][N] =1*N (1<=N<=n)
dp[0][N]=0,dp[M][0]=0 0<= N<=n 0<=M<=n的开方
dp[i][j]=j/(i*i)+dp[i-1][j%(i*i)] 2<=i<=n的开方 1<=j<=n;
private static void extracted() {
int n=16;
int num = (int) Math.sqrt(n);
int [][]dp =new int[num][n];
for(int i=1;i<=n;i++){
dp[1][i]=i;
}
//dp[0][n] dp [n][0] 默认为0无需再初始化
for(int i=2;i<=num;i++){
for(int j=1;j<=n;j++){
dp[i][j]=j/(i*i)+dp[i-1][j % (i * i)];
}
}
System.out.println(dp[num][n]);
}
时间复杂度 O(n*n) 空间复杂度 O(n*n)
优化:仔细观察不难发现 每个的dp只与上行的dp有关
所以我们可以对dp进行优化 一维数组就可满足
因为数组前面索引位置上的数必然是当前可存在因子下因子数目最少的结果
dp结构 int dp [] =new int [n+1];
初始化dp:dp[N] =N (0<=N<=n)
dp公式 添加第i个因子时 数字j 需要的最少因子个数 dp[j]=j/(i*i)+dp[j%(i*i)]; 1<=j<=n
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int num = (int) Math.sqrt(n);
int []dp =new int[n+1];
for(int i=1;i<=n;i++){
dp[i]=i;
}
for(int i=2;i<=num;i++){
for(int j=1;j<=n;j++){
dp[j]=j/(i*i)+dp[j % (i * i)];
}
}
System.out.println(dp[n]);
}
时间复杂度 O(n*n) 空间复杂度 O(n)
时间复杂度目前没有想到如何化简,欢迎评论区大佬来解答