整数的划分(递归法, 打表搜索, 动态规划法)

递归法:

直接举个例子什么是整数的划分。
如有整数 5
接下来对 5 经行划分

5 + 0
4 + 1,
3 + 2
3 + 1 + 1,
2 + 2 + 1
2 + 1 + 1 + 1
1 + 1 + 1 + 1 + 1

7 种 划分方法。

这里直接将用递归解决此问题的思路,
通过看上面的对 5 的划分可以看出, 每种划分中必定有一个最大数(可以有多个)。
我们可以将那个最大的数 成为 m, 而 5 是待划分的数, 称之为 n
接下来将数可以分为俩个部分, m 和 n - mn - m就是除了最大的数其余的数的和了)。

接下来对n ,m,和 n - m经行安排和分析。

  1. n == m 时, 就是最大的数就等于 n 本身, 那么显然就只有一种划分方法就是 n + 0(除非你可以找出第二种,否则不要反驳)。
  2. n < m 时,就是最大的数大于了待划分的数, 那么显然时不存在的,因为不存在负数的划分(如果存在负数,那么也就不用存在这个问题了,答案必定时无穷种划分 )。
  3. n > m 时, 这也是一般的情况,那么就将数分成两个部分{m, 和 n - m},然后分别对两边经行划分,比如(如果此时划分成 3 + 2 ,那么 n - m = 2m = 3, 你可以发现 2 也是可以经行划分的, 那么也就不难理解为啥要n - m经行向下递推了 )。
  4. n == 1 时, 那么就只有一种划分。
  5. m == 1 时, 也只有一种划分。

结合以上情况经行分析:
n == m 时 因为出现了一种划分, 所以要 + 1然后递推下去 (n, m - 1)
n < m 时,那么最大的数应该是 n 所以是 (n, n)
n == 1 或者 m == 1时, 就 + 1, 并且结束,因为 1 不可以再经行划分了。
n > m 时, 经行递推 (n, m -1) + (n - m, m);

接下来将分析换算成代码。

int fun(int n, int m){
   if(n == 1 || m == 1){
   	return 1;
   }
   if(n == m){
   	return fun(n, m - 1) + 1;
   }
   if(n < m){
   // 这里其实应该时fun(n,n);
   // 但是n == m 时就会调用fun(n, m - 1); ,这里可以直接略过这部。
   	return fun(n , n - 1) + 1;
   }
   return fun(n, m - 1) + fun(n - m, m);
}

基于以上代码进行打表, 以增加搜索速度, 实际上就是动态规划了. 但写法还是舒服很多.
速度不亚于动态规划的.

long num[10000][10000] = {0};
long fun(int n, int m){
	if(n <= 0 || m <= 0) return 0;
	if(n == 1 || m == 1) return 1;// 1种划分
	
	if(num[n][m]) return num[n][m]; 
	
	long ans = 0;
	if(n <= m){
		ans += fun(n, n - 1) + 1;
	} else{
		ans += fun(n, m - 1);
		ans += fun(n - m, m);
	}
	
	num[n][m] = ans;
	return ans;
} 



动态规划法:

思想和上面一样,动态规划主要是记录了分化的结果,极大的减少划分次数
一般要把递归代码改写成动态规划就要 逆序 的经行迭代或者搜索
那么如何记录结果呢?
比如 5 ,4经行划分时就需要对5, 31, 1经行划分。
如果在之前就对5, 3经行了划分呢?那么能不能记下来呢?
对于整数的划分,当然是最大值越小越好划分,比如5, 1 就只有一种划分。

那么, 如果一开始就从 5,1 然后 5, 2 然后 5,3 这样经行划分,那么就可以省掉大部分的划分。
由此提高效率。

java代码:

// 动态规划
	static int dp(int n) {
		int result = 0;
		int map[][] = new int[n + 1][n + 1];
		int t = 0;
		for(int i = 1; i <= n; i++) {
			for(int j = 1; j <= i; j++) {
				if(i == j) {// 比如 3, 3. 最大数为3是一种划分
					// 3, 3 = 3, 2 + 1
					map[i][j] = map[i][j - 1] + 1;
				}else if(1 == j) {// 这里i == 1 可以省略
					map[i][j] = 1;
				} else {
					t = i - j;
					// 如果i - j < j 那么就等同于i - j, i - j这种情况, 因为最大值不可能大于待分解值
					if(t < j) {
						map[i][j] = map[i][j - 1] + map[t][t];
					}else {
						map[i][j] = map[i][j - 1] + map[t][j];
					}
				}
			}
		}
		result = map[n][n];
		return result;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦鸢MoYuan

谢谢投喂!!!QWQ!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值