编程之美系列之一——阶乘的运算
前言:
????? 本人一直以來都對算法很有興趣,前些日子拿到《編程之美》這本書,愛不釋手,遂有意將書中的一些本人覺得較有意思的題目以及自己的心得拿出來與大家分享,共同討論,共同進步。
?????需提前要說明的是,本系列文章中許多的問題都直接或間接來自《編程之美》一書。至于解法,則有的來自書中的講解,有的是本人自己的領悟。
???? 閑話不再多說,我們立刻開始。
?
問題描述:
?
問題1的求解:
分析:
解法一:
?????? 首先,最直接的算法當然是直接求出來N!然后看末尾有幾個0就行了。但這里存在兩個問題:
???? (1)不管使用long或者double一定會產生溢出。
???? (2)效率低下。
????? 對于問題(1),我們可以采用字符串存儲的辦法解決,但問題(2)是由本身算法決定的,所以只能采用其他的算法。
那到底有沒有更好的算法呢?我們來分析,N!能產生0的質數組合只能是2 * 5,也就是說當對N!進行質數分解之后,N!末尾0的個位M取決于2的個數X和5的個數Y的最小值,即M = min(X,Y)。又因為能被2整除的數出現的頻率比能被5整除的數高得多,且出現一個5的時,最少會同時出現一個2,所以M = Y。即得出Y的值就可以得到N!末尾0的個數。
計算Y,最直接的方法,就是計算機1…N的因式分解中5的個數,然后求和。
???? 代碼如下:
?????
?
?
解法二:
??????那么還有沒有更簡單點的方法呢?我們想,Y還能怎么樣得到?舉個例子25的階乘中,總共有6個五,其中5,10,15,20,各貢獻一個,25貢獻兩個,也可以說成,5,10,15,20,25各貢獻一個,25又額外貢獻一個,即5的倍數各貢獻一個5,25的倍數各貢獻一個5,即Y=[25/5] + [25/25]。同理,125中,5的倍數各貢獻一個5,25的倍數各貢獻一個5,125的倍數也各貢獻一個5,所以Y=[125/5] + [125/25] + [125/125],所以可得公式:
Y = [N/5] + [N/52] + [N/53] + …
???? 代碼如下:
??????
?
?
問題2的求解:
分析:
?????首先我們來分析一個二進制數乘以2和除以2的過程和結果是怎么樣。
?????一個二進制數乘以2就是把將此二進制數向左移一位,末位補零。除以2時,則要判斷末位是否為0,若為0,向右移一位,若不能為0,則不能被2整除。
???? 所以,其實本問題其實是求N!含有多少個2,最低位1的位置等于N!中含有2的個數加1。
???? 代碼如下:
?????
?
?
?
???? 為了檢驗以上算法的正確性,我運用字符串存儲的方法計算出了任意數的階乘(代碼見附錄),經過測驗,以上算法計算結果正確。
?
?
附錄:
import?java.io.*;
import?java.util.*;
?
/*
* 此類為計算任意數階乘,采用大數相乘,大體算法為,將接收到兩個數字字符串存放在兩個鏈表中,每個鏈表的一個節點代表一位數字,
?* 鏈表的順序是從后往前。然后分別用第二個鏈表的每一位數字乘以第一個鏈表的整體,再將得到的鏈表相加即為所求。
?*
?*/
?
public?class?Fantorial
{
????public?static?void?main(String[] args)
??? {
?????? System.out.print("輸入n: ");
????? BufferedReader br =?new?BufferedReader(new?InputStreamReader(System.in));
???????try
?????? {??
?????????? String s = br.readLine();?? //
?????????? String s = getResult (new Long(s).longValue());
?????????? System.out.println(s);
?????? }
???????catch(Exception e)
?????? {
?????????? e.printStackTrace();
?????? }
??? }
???
/*
?*計算階乘
?*/
????public?static?String getResult(long?n)
??? {
???????if(n == 0)
???????????return?"1";
???????else
?????? {
???????return?BigCount.mul(new?Long(n).toString(),?getResult(n - 1));
?????? }??
??? }
???
????public?static?String mul(String s1, String s2)
??? {
?????? LinkedList<Integer> nl1,nl2;
?????? nl1 =?stringToList(s1);
?????? nl2 =?stringToList(s2);
?????? LinkedList<Integer> temp =?mul(nl1, nl2);
?????? String s =?listToString(temp);
???????return?s;
??????
??? }
???
??? /*
??? ?* 將鏈表轉化成字符串
??? ?*/
????public?static?String listToString(LinkedList<Integer> nl)
??? {
?????? StringBuilder s =?new?StringBuilder();
???????for(int?i = nl.size() - 1; i >= 0; i--)
?????? {
?????????? s.append(nl.get(i));
?????? }??
???????return?s.toString();
??? }
???
??? /*
??? ?* 將字符串轉化成鏈表
??? ?*/
????public?static?LinkedList<Integer> stringToList(String s)
??? {
?????? LinkedList<Integer> nl =?new?LinkedList<Integer>();
?????? //按從后到前存入鏈表
???????for(int?i=s.length()-1;i>=0;i--)
?????? {
?????????? nl.add(Character.getNumericValue(s.charAt(i)));
?????? }
???????return?nl;
??? }
???
??? /*
??? ?* 計算兩鏈表相乘
??? ?*/
????public?static?LinkedList<Integer> mul(LinkedList<Integer> nl1,LinkedList<Integer> nl2)
??? {
?????? LinkedList<Integer> temp =?new?LinkedList<Integer>();
?????? LinkedList<Integer> temp0 =?null;
?????? temp.add(0);
???????for(int?i=0;i<nl1.size();i++)
?????? {
?????????? temp0 =?mul(nl2, nl1.get(i).intValue());
?????????? //不同位的數字有不同的權值,如123中最后一個3就代表3,2代表20,1代表100
???????????for(int?j=0;j<i;j++)
?????????? {
????????????? temp0 =?mul(temp0, 10);?
?????????? }
?????????? temp =?plus(temp ,temp0);
?????? }
???????return?temp;
??? }
???
??? /*
??? ?* 計算一個鏈表和一個數相乘
??? ?*/
????public?static?LinkedList<Integer> mul(LinkedList<Integer> nl,int?k)
??? {
???????int?temp = 0;
???????int?x;
?????? LinkedList<Integer> tempList =?new?LinkedList<Integer>();
??? ????for(int?i=0;i<nl.size();i++)
?????? {
?????????? x = nl.get(i).intValue() * k + temp;
?????????? tempList.add(x % 10);
?????????? temp = x / 10;
?????? }
???????if(temp != 0)
?????????? tempList.add(temp);
???????return?tempList;
??? }
???
??? /*
??? ?* 計算機兩鏈表相加
??? ?*/
????public?static?LinkedList<Integer> plus(LinkedList<Integer> nl1,LinkedList<Integer> nl2)
??? {
?????? LinkedList<Integer> nl =?new?LinkedList<Integer>();
?????? LinkedList<Integer> tempList =?new?LinkedList<Integer>();
???????int?x;
???????int?temp = 0;
???????int?i;
???????for(i=0;i<nl1.size() && i<nl2.size();i++)
?????? {
?????????? x = nl1.get(i).intValue() + nl2.get(i).intValue() + temp;
?????????? nl.add(x % 10);
?????????? temp = x / 10;
?????? }
???????if(i == nl1.size() && i == nl2.size())
?????? {
???????????if(temp != 0)
????????????? nl.add(temp);
?????? }
???????else?if(i == nl1.size())
?????? {
???????????for(int?j=i;j<nl2.size();j++)
?????????? {
????????????? tempList.add(nl2.get(j).intValue());
?????????? }
?????????? tempList =?plus(tempList,temp);
???????????for(int?j=0;j<tempList.size();j++)
?????????? {
????????????? nl.add(tempList.get(j).intValue());
?????????? }
???
?????? }
???????else?if(i == nl2.size())
?????? {
???????????for(int?j=i;j<nl1.size();j++)
?????????? {
????????????? tempList.add(nl1.get(j).intValue());
?????????? }
?????????? tempList =?plus(tempList,temp);
???????????for(int?j=0;j<tempList.size();j++)
?????????? {
????????????? nl.add(tempList.get(j).intValue());
?????????? }
???
?????? }
???????return?nl;
??? }
???
??? /*
??? ?* 計算一個鏈表和一個數字相加
??? ?*/
????public?static?LinkedList<Integer> plus(LinkedList<Integer> nl,int?k)
??? {
???????int?temp = k;
???????int?x;
???????for(int?i=0;i<nl.size();i++)
?????? {
?????????? x = nl.get(i).intValue() + temp;
?????????? nl.set(i,x % 10);
?????????? temp = x / 10;
?????? }
???????if(temp != 0)
?????????? nl.add(temp);
???????return?nl;
??? }
}
總結
以上是生活随笔為你收集整理的编程之美系列之一——阶乘的运算的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: as工程放到源码编译_Flutter源码
- 下一篇: 货车定位服务器维护是什么意思,有关货车日