您的位置:首页 > 其它

对一个正整数n,算得到1需要的最少操作次数。

2014-08-05 22:08 260 查看
实现一个函数,对一个正整数n,算得到1需要的最少操作次数。操作规则为:如果n为偶数,将其除以2;如果n为奇数,可以加1或减1;一直处理下去

int func(unsigned int n)
{
if(n == 1)
    return 0;
if(n % 2 == 0)
    return 1 + func(n/2);
int x = func(n + 1);
int y = func(n - 1);
if(x > y)
    return y+1;
else
    return x+1;
}

假设n表示成二进制有x bit,可以看出计算复杂度为O(2^x),也就是O(n)。

将n转换到二进制空间来看(比如7为111,6为110):

- 如果最后一位是0,则对应于偶数,直接进行除2操作。

- 如果最后一位是1,情况则有些复杂。

**如果最后几位是???01,则有可能为???001,???1111101。在第一种情况下,显然应该-1;在第二种情况下-1和+1最终需要的步数相同。所以在???01的情况下,应该选择-1操作。

**如果最后几位是???011,则有可能为???0011,???11111011。在第一种情况下,+1和-1最终需要的步数相同;在第二种情况下+1步数更少些。所以在???011的情况下,应该选择+1操作。

**如果最后有更多的连续1,也应该选择+1操作。

如果最后剩下的各位都是1,则有11时应该选择-1;111时+1和-1相同;1111时应选择+1;大于四个1时也应该选择+1;

int func(unsigned int n)
{
if(n == 1)
    return 0;
if(n % 2 == 0)
    return 1 + func(n/2);
if(n == 3)
    return 2;
if(n&2)
    return 1 + func(n+1);
else
    return 1 + func(n-1);
}

由以上的分析可知,奇数的时候加1或减1,完全取决于二进制的后两位,如果后两位是10、00那么肯定是偶数,选择除以2,如果后两位是01、11,那么选择结果会不一样的,如果是*****01,那么选择减1,如果是*****11,那么选择加1,特殊情况是就是n是3的时候,选择减1操作。

非递归代码如下:

// 非递归写法
int func(int n)
{
int count = 0;
while(n > 1)
{
    if(n % 2 == 0)
        n >>= 1;
    else if(n == 3)
        n--;
    else
    {
        if(n&2)      // 二进制是******11时
            n++;
        else         // 二进制是******01时
            n--;
    }
    count++;
}
return count;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐