整数分区(求将整数拆分成任意个数正整数的方法个数)codewars 爆炸求和
依舊是codewars上面的題目,獻上鏈接
codewars 爆炸總和
整數(shù)分區(qū)
整數(shù)n的分區(qū)是正整數(shù)(不一定是不同的)的無序集合,其加起來為n。這種分區(qū)的數(shù)量通常表示為p(n)。函數(shù)p稱為分區(qū)函數(shù),其值列表如下。這從p(0)= 1開始,因為只有一個正整數(shù)的集合,其總和為零(即空集合)。
n:p(n)0:1 1:1 //12:2 //1+1 23:3 //1+1+1 1+2+1 34:5 //1+1+1+1 1+1+2 3+1 2+2 45:7 //1+1+1+1+1 1+1+1+2 1+1+3 1+2+2 4+1 2+3 56:11 //1+1+1+1+1+1 1+1+1+1+2 1+1+1+3 1+ 1+2+2 1+1+4 1+2+3 1+5 2+2+2 2+4 3+3 6...數(shù)學規(guī)律
在寫代碼之前應(yīng)該先搞懂數(shù)學分區(qū)的數(shù)學規(guī)律。
假設(shè)將n進行分區(qū),通過規(guī)律我們可以知道n各分區(qū)中包含n-1的分區(qū)加上1,整理之后得出以下規(guī)律:
p(n) = p(n-1)
+p(n-2) - p(n-2)中有“+1”的分區(qū)方法
+p(n-3) - p(n-3)中有“+1”的分區(qū)方法 - p(n-3)中有“+2”的分區(qū)方法
…
直到 n-i < i
| 1 | 2 | 3 | 5 | 7 | 11 | 15 | 22 | 30 | 42 |
| +0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| +1 | 0 | 1 | 2 | 3 | 5 | 7 | 11 | 15 | 22 | 30 | p(n-1) |
| +2 | 0 | 0 | 0 | 1 | 1 | 2 | 2 | 4 | 4 | 7 | w[i-1][n-1]-w[i-1][n-2] |
| +3 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 2 | 2 | w[i-1][n-1]-w[i-1][n-3] |
| +4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | w[i-1][n-1]-w[i-1][n-4] |
| +5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | w[i-1][n-1]-w[i-1][n-5] |
| … | |||||||||||
| +i | w[i-1][n-1]-w[i-1][n-i] |
則
p(n)=∑w[i][n](0≤i≤(n+1)/2)p(n)=\sum w[i][n](0≤i≤(n+1)/2) p(n)=∑w[i][n](0≤i≤(n+1)/2)
找出規(guī)律之后我們就可以寫代碼了
代碼架構(gòu)
可以看出解決整數(shù)分區(qū)最重要的兩個函數(shù)一個是計算p(n)的求和公式,一個是計算w[n][i]的函數(shù)。
//p(n)加和函數(shù) using ull = unsigned long long; ull exp_sum(ull n) {ull num = 0;for (ull i = 0; i <= n/ 2; i++)//當i>n/2,w[n][i]=0{num += cal_w(n, i);}sum_vec.push_back(num); return num; }//w[n][i]的計算函數(shù) ull cal_w(ull n, ull i) {if (n==0||i==0){return 1;}if (i==1){return sum_vec[n - 1];}if (i>n/2){return 0;}return add(n - 1, i - 1) - add(n - i, i - 1); };在頁面上提交的時候發(fā)現(xiàn)有超時,那么說明要改數(shù)據(jù)結(jié)構(gòu)了。
解決函數(shù)運行性能,常常用內(nèi)存換運行時間,也就是將以前計算過得數(shù)據(jù)存儲出來,方便使用。
加入兩個容器:
代碼更改如下:
//前向聲明ull exp_sum(ull n); ull cal_w(ull n, ull i);//w[n][i]的計算函數(shù) ull cal_w(ull n, ull i) {if (n>=w.size())//如果w中沒有n的相關(guān)加和數(shù)據(jù),先進行w[n]的計算{w.push_back(vector<ull>(n, 0));w.back()[0] = 1;w.back()[1] = p[n - 1];for (ull i = 2; i <= n / 2; i++){w.back()[i]= cal_w(n - 1, i - 1) - cal_w(n - i, i - 1);}}if (i>=w[n].size()&&i>n/2){return 0;}return w[n][i];//返回w[n][i] };//p(n)加和函數(shù) ull exp_sum(ull n) {while (n>=p.size()){ull num = 0;for (ull i = 0; i <= p.size()/ 2; i++)//p[n]不存在時,先將n以及n以前的所有數(shù)據(jù)補齊{num += cal_w(p.size(), i);}p.push_back(num);}return p[n]; }然后問題就完美解決了
貼上整數(shù)分區(qū)的值列表,可以用來調(diào)試
整數(shù)分區(qū)
總結(jié)
以上是生活随笔為你收集整理的整数分区(求将整数拆分成任意个数正整数的方法个数)codewars 爆炸求和的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BADI 构建方法(NEW BADI 实
- 下一篇: 位图与矢量图的区别