如果n为偶数,则将它除以2,
如果n为奇数,则将它加1或者减1。
问对于一个给定的n,怎样才能用最少的步骤将它变到1。
其实这个问题就是如何将整数变量乘上整数常数问题转化为最少的移位运算和加法运算问题. 假设一个计算机只提供加减法和移位一位的指令,那么这个问题就相当于如何用最少的加减法和移位指令来计算乘上一个整数常数的算法.
这个算法很简单:
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,移位指令都可以移动任何数目的比特位,这时,就没有上面简洁的算法了,一般来说,我们将需要使用动态规划来计算最优方案