获得数字的最短可能序列

时间:2016-03-13 17:49:29

标签: algorithm performance

序列的第一个元素是1A[0]=1 A[i+1]可以是2A[i]A[i]+1

我们必须找到最短的序列。

例如:

If N is 18
 A[0]=1, A[1]=2,4,8,9,18

所以我的代码基本上就是。

 int count = 0;
 for (int i = N, i != 1;){
 if (i % 2 == 0) { 
     i /= 2;
     ++count;
 } else{
     --i;
     ++count;
 }
 return count;

正如您所看到的,此算法非常简单,并且将返回最短的长度。但是,最差的时间复杂度是O(N)

有没有办法让它O(logN)

1 个答案:

答案 0 :(得分:2)

您的算法已经是O(log(N))。要看到这一点,您的算法可以像这样重写:

 int count = 0;
 for (int i = N; i != 1;) {
   if (i % 2 == 1) { 
     --i
     ++count;
   }
   i /= 2;
   ++count;
 }
 return count;

对于每个位,您要么除以2,要么减去1并除以2。由于每位操作的次数不依赖于N的大小,因此时间为O(log(N))。

有关其原因的一些细节

如果你考虑二进制。乘以2是将位左移一位。添加一个是将最右边的位设置为1。因此,只需读取N的二进制值即可找到操作序列。

N = 18是二进制的10010,所以我们有

1 = starting value:            1
0 = multiply by 2 :            2
0 = multiply by 2 :            4
1 = multiply by 2 and add one: 8,9
0 = multiply by 2 :            18

解决方案不一定是唯一的,但它始终至少与任何其他解决方案一样短。要了解原因,您只需要观察连续两次添加相当于将第1位添加到第1位并将第0位归零:

xxx01 -> xxx10

但是你可以通过先添加一个来获得相同的结果,所以连续两次添加一个没有任何好处。因此,最佳操作序列包括重复乘以2并且可选地在每次乘法之间加1。