暴力递归
import java.util.ArrayList;
import java.util.List;
public class SplitNumber2 {
public static int ways1(int n){
if(n < 1){
return 0;
}
return process(1,n);
}
public static int process(int pre,int rest){
if(rest == 0){
return 1;
}
if(pre > rest){
return 0;
}
int ways = 0;
for(int i = pre;i <= rest;i++){
ways += process(i,rest-i);
}
return ways;
}
}
dp
public static int way2(int n){
int[][] dp = new int[n+1][n+1];
for(int pre = 1;pre <= n;pre++){
dp[pre][0] = 1;
}
for(int pre = n;pre>=1;pre--){
for(int rest = pre;rest<=n;rest++){
int way = 0;
for(int i = pre;i <= rest;i++){
way += dp[i][rest-i];
}
dp[pre][rest] = way;
}
}
return dp[1][n];
}
可以画图找规律 优化
dp[i][j] dp[n][k]
dp[7][3]的第一种可能性是dp[6][3] 这种情况就是把7放在最后
依赖dp[6][2] 这种情况把7放在倒数第二位
依赖dp[6][1] 这种情况把7放在导数第三位
依赖dp[6][0] 这种情况把7放在导数第四位
dp[6][7] 不依赖dp[6][0] 会存在截掉一部分的情况
行列模型 关注开头和结尾
public class KInversePairs2 {
public static int dp(int N,int K){
if(N < 1 || K < 0){//可以加一个判断上限的,因为逆序数有上限的 对于一个固定的数
return 0;
}
if(K == 0){
return 1;
}
int[][] dp = new int[N+1][K+1];
dp[1][0] = 1;
for(int i = 2;i <= N;i++){
dp[i][0] = 1;
}
for(int i = 2;i <= N;i++){
for(int j = 1;j<=K;j++){
//视频讲的这个地方可能笔误了
//dp[i][j] i < j dp[i-1][j...0]
//dp[i][j] i >= j dp[i-1][j-i+1]
//以上两种情况合在一起
//突然顿悟 ,比如dp[7][3] 为什么依赖dp[6][2]
// 这个是把7放在倒数第二个位置 为1种逆序对,
//然后dp[6][2]为原本的2种逆序对。组合在一起构成了dp[7][3]的三种逆序对
for(int s= j; s>= Math.max(0,j-i+1);s--){
dp[i][j] += dp[i-1][s];
}
//下面的代码为优化后的。可以通过计算得出下面规律
/*
if(i > j){
dp[i][j] = dp[i][j-1] + dp[i-1][j];
}
if(i <= j){
dp[i][j] = dp[i-][j-1] + dp[i][j-1] - dp[i-1][j-1];
}
//也可简写为
dp[i][j] = dp[i][j-1] + dp[i-1][j] -(i <=j ? dp[i-1][j-1] : 0);
*/
}
}
return dp[N][K];
}
}