遞歸法:
直接舉個例子什麼是整數的劃分。
如有整數 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 - m (n - m就是除了最大的數其餘的數的和了)。
接下來對n ,m,和 n - m經行安排和分析。
- 當 n == m 時, 就是最大的數就等於 n 本身, 那麼顯然就只有一種劃分方法就是 n + 0(除非你可以找出第二種,否則不要反駁)。
- 當 n < m 時,就是最大的數大於了待劃分的數, 那麼顯然時不存在的,因爲不存在負數的劃分(
如果存在負數,那麼也就不用存在這個問題了,答案必定時無窮種劃分)。 - 當 n > m 時, 這也是一般的情況,那麼就將數分成兩個部分{m, 和 n - m},然後分別對兩邊經行劃分,比如(如果此時劃分成 3 + 2 ,那麼 n - m = 2, m = 3, 你可以發現 2 也是可以經行劃分的,
那麼也就不難理解爲啥要n - m經行向下遞推了)。 - 當 n == 1 時, 那麼就只有一種劃分。
- 當 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, 3 和 1, 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;
}