在CSDN看到一個問題:
如果n為偶數,則將它除以2,
如果n為奇數,則將它加1或者減1。
問對於一個給定的n,怎樣才能用最少的步驟將它變到1。
http://community.csdn.net/Expert/topic/5294/5294802.xml
其實這個問題就是如何將整數變數乘上整數常數問題轉化為最少的移位元運算和加法運算問題. 假設一個電腦只提供加減法和移位一位的指令,那麼這個問題就相當於如何用最少的加減法和移位指令來計算乘上一個整數常數的演算法.
這個演算法很簡單:
int cnt(int x){ int m; if(x==1)return 0; m=x%4; if(m==0||m==2)return cnt(x/2)+1; if(m==1)return cnt(x-1)+1; return cnt(x+1)+1;//if(m==3). }也就是說,在x是偶數時採用除2。x是奇數(x>=5),如果除4餘1採用減1,如果除4餘3採用加1。i)需要證明,對於x=2k,採用加1或減1的方案都沒有除2好。 i1) 2k=>k比2k=>2k+1好, 2k+1下一步不能再到2k+1-1=2k(走回頭路了),所以這個方案比如是兩次後變成 2k=>2k+1=>...=>2k+2s=>k+s (2s+1步s>=1) 而 2k=>k的方案到k+s只需要2k=>k=>k+1=>...=>k+s (s+1步) 所以2k=>k的方案必然好於2k=>2k+1的方案。 i2)2k=>k比2k=>2k-1好 同樣,對於2k=>2k-1的方案,必然如下變換: 2k=>2k-1=>....=>2k-2s=>k-s (2s+1步變換) 而2k=>k的方案可以通過s+1步達到同樣目的 2k=>k=>k-1=>...=>k-s (s+1步) 所以2k=>k的方案必然好於2k=>2k-1方案。由此,我們得到第一個結論:對於偶數,必然採用除2的方案。ii)我們來證明對於x=4k+1的情況,採用x-1的方案不差於採用x+1的方案。 由結論1,採用x+1的方案必然是 4k+1=>4k+2=>2k+1 然後必然是 4k+1=>4k+2=>2k+1=>2k+2=>k+1或 4k+1=>4k+2=>2k+1=>2k=>k 所以採用這個方案必然是通過4步到達k+1或k 但是通過x=>x-1方案我們可以 4k+1=>4k=>2k=>k 4k+1=>4k=>2k=>k=>k+1 分別通過3步或4步到達k或k+1,所以我們知道,對於x=4k+1,x=>x-1的方案不差於x=>x+1的方案。所以為了達到最優結果我們總可以採用x=>x-1方案。iii)最後一步證明對於x=4k+3,x=>x+1方案不差於x=>x-1方案。 對於x=>x-1方案,根據結論1,其變換必然是 4k+3=>4k+2=>2k+1,所以下面兩步變換必然導致 4k+3=>4k+2=>2k+1=>2k+2=>k+1 或 4k+3=>4k+2=>2k+1=>2k=>k 所以同樣是經過4步變換得到k或k+1 而採用x=>x+1的方案,我們總可以使用 4k+3=>4k+4=>2k+2=>k+1 4k+3=>4k+4=>2k+2=>k+1=>k 經過3步或4步到達k+1或k,所以對於x=4k+3,採用x=>x+1方案不差於x=>x-1方案。由上面結論我們可以知道,使用前面的演算法必然能夠找到最優結果。時間複雜度是O(log(n)),空間複雜度是O(log(n))(因為採用了遞迴),實際上,這個遞規是尾遞規,通過簡單的最佳化,可以到達時間複雜度位O(log(n))但是空間複雜度為O(1)的結果。當然對於實際上的CPU,移位指令都可以移動任何數目的位元位,這時,就沒有上面簡潔的演算法了,一般來說,我們將需要使用動態規劃來計算最優方案