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

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

例子:
func(7) = 4,可以证明最少需要4次运算
n = 7
n-1 6
n/2 3
n-1 2
n/2 1
要求:实现函数(实现尽可能高效) int func(unsign int n);n为输入,返回最小的运算次数。给出思路(文字描述),完成代码,并分析你算法的时间复杂度。
答:

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;  
}

另外一种写法如下:

// 非递归写法  
int func(int n)  
{  
    int count = 0;  
    while(n > 1)  
    {  
        if(n % 2 == 0)            // n % 4等于0或2  
            n >>= 1;  
        else if(n == 3)  
            n--;  
        else  
            n += (n % 4 - 2);     // n % 4等于1或3  
        count++;  
    }  
    return count;  
} 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值