用Java實(shí)現(xiàn)大數(shù)階乘
隨著計(jì)算機(jī)硬件的不斷升級(jí),大數(shù)計(jì)算已不再是問題。但在某些場(chǎng)合下,我們還是需要自己編寫程序來處理大數(shù)計(jì)算問題。比如在一些面試題中,可能會(huì)涉及到大數(shù)階乘的計(jì)算問題。本文將介紹使用Java來實(shí)現(xiàn)大數(shù)階乘的方
隨著計(jì)算機(jī)硬件的不斷升級(jí),大數(shù)計(jì)算已不再是問題。但在某些場(chǎng)合下,我們還是需要自己編寫程序來處理大數(shù)計(jì)算問題。比如在一些面試題中,可能會(huì)涉及到大數(shù)階乘的計(jì)算問題。本文將介紹使用Java來實(shí)現(xiàn)大數(shù)階乘的方法。
計(jì)算Java提供的數(shù)據(jù)類型可以處理的最大范圍
在開始介紹大數(shù)階乘的具體實(shí)現(xiàn)前,我們需要先了解一下Java提供的數(shù)據(jù)類型可以處理的數(shù)據(jù)范圍。Java中提供了兩種基本數(shù)據(jù)類型:int和long。它們分別占用4個(gè)字節(jié)和8個(gè)字節(jié)。它們所能表示的數(shù)值范圍如下:
- int:-2,147,483,648 ~ 2,147,483,647,最多可計(jì)算12的階乘。
- long:-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807,最多可計(jì)算20的階乘。
如果我們要計(jì)算更大范圍的數(shù)字的階乘(例如50的階乘),就需要使用自定義的數(shù)字類型來表示這個(gè)數(shù)字了。
使用鏈表表示法自定義數(shù)字類型
為了表示一個(gè)大數(shù),我們可以使用鏈表的方式,將每一位數(shù)字從低到高存儲(chǔ)到鏈表中。如下所示:
數(shù)字:1234 鏈表表示為:1->2->3->4
數(shù)字:788996 鏈表表示為:7->8->8->9->9->6
下面是用Java代碼實(shí)現(xiàn)的鏈表節(jié)點(diǎn)類:
private static class ListNode {
int val; // 鏈表節(jié)點(diǎn)的值
ListNode next; // 下一個(gè)節(jié)點(diǎn)
public ListNode(int val) {
val;
}
// 重新 toString 方法,方便最后輸出整個(gè)鏈表
@Override
public String toString() {
StringBuilder b new StringBuilder();
(val);
ListNode nextNode next;
while (null ! nextNode) {
(",").append();
nextNode ;
}
return ();
}
}
實(shí)現(xiàn)大數(shù)相乘
在實(shí)現(xiàn)大數(shù)階乘之前,我們需要先掌握如何實(shí)現(xiàn)大數(shù)相乘。我們可以把一個(gè)大于等于10的數(shù)字拆分為多個(gè)小于10的數(shù)字,然后對(duì)每個(gè)小數(shù)字分別進(jìn)行計(jì)算,最后將它們的結(jié)果相加。具體步驟如下:
- 將數(shù)字進(jìn)行拆分,將一個(gè)大于等于10的數(shù)字,拆分為多個(gè)小于10的數(shù)字。
- 將每一個(gè)小于10的數(shù)字和我們的大數(shù)相乘。
- 將相乘的結(jié)果進(jìn)行累加,即得到最終結(jié)果。
拆分?jǐn)?shù)字的具體實(shí)現(xiàn)可以參考下面的代碼:
private int[] scatterNumber(int num) {
// 注意要除以9.0,否則兩個(gè)整數(shù)相除一定返回一個(gè)整數(shù)
int resultLength (int) Math.ceil(num / 9.0);
int[] result new int[resultLength];
int index 0;
while (num > 10) {
result[index] 9;
num num - 9;
index ;
}
if (num > 0) {
result[index] num;
}
return result;
}
實(shí)現(xiàn)大數(shù)相乘的代碼如下:
private ListNode multipleSingleNum(ListNode ln, int num) {
ListNode result new ListNode(0);
ListNode currentNode result;
int carryBit 0; // 進(jìn)位
while (null ! ln) {
int mVal * num carryBit;
carryBit mVal / 10;
mVal mVal % 10;
ListNode theNode new ListNode(mVal);
theNode;
currentNode ;
ln ;
}
// 注意最后要看看是否還有有效的進(jìn)位沒有處理
if (carryBit > 0) {
new ListNode(carryBit);
}
return ;
}
private ListNode multipleNumber(ListNode ln, int num) {
// 將數(shù)字進(jìn)行拆分
int[] allUsedNums scatterNumber(num);
ListNode result new ListNode(0);
for(int usedNum : allUsedNums) {
// 將每一個(gè)小于10的數(shù)字和我們的大數(shù)相乘
ListNode mulResult multipleSingleNum(ln, usedNum);
// 將相乘的結(jié)果進(jìn)行累加
result addTwoNumbers(result, mulResult);
}
return result;
}
當(dāng)兩個(gè)大數(shù)長度不一致時(shí),我們可以在短的那條大數(shù)前補(bǔ)0,使它與另一個(gè)大數(shù)長度一樣。具體實(shí)現(xiàn)可以參考下面的代碼:
private ListNode addTwoNumbers(ListNode l1, ListNode l2) {
int firstNodeVal ;
int carryBit firstNodeVal / 10; // 進(jìn)位
firstNodeVal firstNodeVal % 10; // 當(dāng)前位的值
ListNode result new ListNode(firstNodeVal); // 最后的計(jì)算結(jié)果
ListNode computePoint result; // 指向當(dāng)前的計(jì)算節(jié)點(diǎn)
l1 ; // 移到下一個(gè)節(jié)點(diǎn)
l2 ; // 移到下一個(gè)節(jié)點(diǎn)
while (null ! l1 || null ! l2) {
int l1Val null l1? ;
int l2Val null l2? ;
int sum l1Val l2Val carryBit; // 計(jì)算和,要加上進(jìn)位
carryBit sum / 10; // 重新計(jì)算進(jìn)位
sum sum % 10; // 當(dāng)前位的和
new ListNode(sum);
computePoint ; // 移到下一個(gè)節(jié)點(diǎn)
l1 null l1? ; // 移到下一個(gè)節(jié)點(diǎn)
l2 null l2? ; // 移到下一個(gè)節(jié)點(diǎn)
}
// 如果最后進(jìn)位有結(jié)余,則需要將其設(shè)置到新節(jié)點(diǎn)中
if (carryBit > 0) {
new ListNode(carryBit);
}
return result;
}
測(cè)試
我們分別計(jì)算10、20、50的階乘,并驗(yàn)證運(yùn)行結(jié)果是否正確。具體代碼如下:
public static void main(String[] args) {
Solution solution new Solution();
int n1 10;
ListNode result1 solution.factorial(n1);
(n1 "! " ());
int n2 20;
ListNode result2 solution.factorial(n2);
(n2 "! " ());
int n3 50;
ListNode result3 solution.factorial(n3);
(n3 "! " ());
}
輸出結(jié)果如下:
10! 3628800
20! 2432902008176640000
50! 30414093201713378043612608166064768844377641568960512000000000000
以上就是使用Java實(shí)現(xiàn)大數(shù)階乘的方法。通過使用鏈表表示法和自定義的大數(shù)計(jì)算方法,我們可以輕松地處理大數(shù)計(jì)算問題,并得到準(zhǔn)確的結(jié)果。