作者:丁宋濤
數組:加一
題干:
給定一個由整數組成的非空數組所表示的非負整數,在該數的基礎上加一。
最高位數字存放在數組的首位,數組中每個元素只存儲一個數字。
你可以假設除了整數?0 之外,這個整數不會以零開頭。
參考樣例:
示例1:
輸入:?[1,2,3]
輸出:?[1,2,4]
解釋:輸入數組表示數字123。
示例2:
輸入:?[4,3,2,1]
輸出:?[4,3,2,2]
解釋:輸入數組表示數字4321。
這道題是一道數組的基礎題,其本質是一道模擬計算題。
這道題有一定的工程應用意義,大家都知道,計算機的浮點數運算有誤差,究其細節有相當數量的開發者卻往往不求甚解。請看:
做開發的朋友都知道計算機在程序處理中,都是將十進制數轉成二進制數進行運算的。對于這種轉化,其方法就是除2逆向取余法,例如:
十進制數13轉成二進制的方法就是
轉化成數學表達式就是(13) ??=(1101) ?
對于十進制小數轉化成二進制小數使用的方法是乘2正向取整法,比如十進制的0.75
即(0.75) ??=(0.11) ?
如果,我們考慮下將十進制的0.6轉化成二進制呢?如果依然使用乘二正向取整法會發生什么呢?
如果從數學上講,(0.75) ??=(0.1001) ?
為什么會出現這種循環表示呢?因為數學上有證明,十進制表示法與二進制表示法,僅僅在整數范圍內才有明確的對應的關系,而小數部分是做不到的。因此,在采用二進制運算上,計算機的數值求解是有缺陷的。
意識到這一點,我們就會問那么是不是我們現在和小數點相關的運行都是不可靠的呢?顯然不可能,最常見的就是我們的金融活動。大凡和交易有關的數據,那是一個數字都不能出錯的,那么他們背后的計算過程又是如何保證的呢?
答案就是模擬計算。
在小學數學課本上就教過這樣的案例:123.4+5.67,我們來看,加數與被加數的位數并不相同,小學老師在教學中一定會強調對齊小數點,其過程如下:
這個在計算機中有一個術語叫做對階。所謂階就是進制,十進制的階就是10,二進制的階就是2,具體的數學表達就是
123.4?=?1×102+2×101+3×100+4×10-1
5.67=5×100+6×10-1+7×10-2
我們知道計算機的整數運算是沒有缺陷的,如果我們這樣做,是不是就可以達到精確求解的目的了?
123.4+5.67=(12340+567)×10-2=12907×10-2=129.07
這就是精度計算中的常用的計算思想,這也是為什么在以Java為核心語言中做交易系統中,金額通常不用float,double而用decimal類型的原因。
明白了這個知識,我們就知道了這個看似普通的題目,其實是企業開發商用軟件中的一個現實問題。那么,在現實計算中,人們又是如何來處理上述的對階、運算的過程呢?答案就是數組。我們用數組來模擬每一位,然后用小學數學課本教授的方法,手工計算出就可以了。
下面回到這個題目:題目的函數簽名是這樣的:vector<int> plusOne(vector<int>& digits)
傳入的參數是digits,是一個整型的向量,其位數按照角標升序排列,即角標0對應的是數字的最高位,最后一位表示的數字的最低位,比如參考樣例:[1,2,3],他表示的是十進制123,角標0對應的是百位1,角標2對應的是個位3.模擬十進制計算的過程,就是逢10進位,這道題我們首先要找到最低位,如果最低位不是9,直接取出角標對應的數值加1即可,如果是數字的9的話,那么直接將其改為0,并向其上一位角標對應的數字加1.需要注意的細節是,如果這個數字恰好是[9,9,9],那么返回值應當增加1位得到[1,0,0,0]。為了方便編程,我們從最后一位開始。代碼如下:
1?vector<int> plusOne(vector<int>& digits) {
2????????int n = digits.size();
3????????for(int i=n-1;i>=0;i--){
4????????????if(digits[i] == 9)
5????????????????digits[i] =0;
6????????????else {
7????????????????digits[i]++;
8????????????????return digits;
9????????????} ???????????
10????????}
11????????digits[0] =1;
12????????digits.push_back(0);
13????????return digits;
14?}
第2行,首先獲得當前向量digits的長度,并將其復制給n,然后從角標n-1開始,逆向遍歷整個數組,由于i是從n-1開始,我們先判斷當前位置是否是9,如果是9,那么就把把當前位置置0,并向前遍歷到前一個位置,只要前一個位置不是9,那么就把此時的位置加1,然后返回。如果全體循環結束都沒有返回,那么說明傳入的必然是999這種類型的。那么出了循環之后,先把角標0改為1,并再增加一個0,就完成了全部的計算過程。