leetcode 991. 坏了的计算器

https://leetcode-cn.com/problems/broken-calculator/comments/

在显示着数字的坏计算器上,我们可以执行以下两种操作:

  • 双倍(Double):将显示屏上的数字乘 2;
  • 递减(Decrement):将显示屏上的数字减 1 。

最初,计算器显示数字 X

返回显示数字 Y 所需的最小操作数。

 

示例 1:

输入:X = 2, Y = 3
输出:2
解释:先进行双倍运算,然后再进行递减运算 {2 -> 4 -> 3}.

示例 2:

输入:X = 5, Y = 8
输出:2
解释:先递减,再双倍 {5 -> 4 -> 8}.

示例 3:

输入:X = 3, Y = 10
输出:3
解释:先双倍,然后递减,再双倍 {3 -> 6 -> 5 -> 10}.

示例 4:

输入:X = 1024, Y = 1
输出:1023
解释:执行递减运算 1023 次

 

提示:

  1. 1 <= X <= 10^9
  2. 1 <= Y <= 10^9

 

首先这一题的思路是

先逆向思维,把题目倒过来,理解为X不变,Y只能进行除2或者+1运算,要使得最后两者结果相等。

为什么要进行颠倒呢,因为倒过来会发生的情况比较少,如果是X进行*2或者-1运算运算,那么在X为任何值的时候都可以进行两种操作,而倒过来计算,Y进行除2或者+1运算,那么当Y为奇数的时候,就不能进行除2运算。这样就减少了一些可能性。

如果把题目倒过来后,总共有三种情况

第一种情况,如果Y<X,那么只能通过Y递增运算来接近了,这种情况下,如果使用除2 运算,无论在哪一步进行除2都会使得Y越来越远离X

第二种情况,是X<Y,并且Y是奇数,如果Y是奇数,那么就不能进行除2运算了,因为会无法整除,因此在这里如果Y为奇数,那么只能进行递增运算,把Y变成偶数(然后下一步才可以进行除2运算)

第三种情况,也就是X<Y,并且Y是偶数,这个情况下,即可用递增运算,也可以用除2运算,在这种时候采用除2运算优于+1运算,因此这种情况直接采用除2运算,至于为什么会这样?

这里来推论一下,首先因为Y是偶数,因此如果进行递增运算,后无法进行除2运算,这种情况下,也就是递增运算最少需要用两次(因为X<Y因此还需要进行除2运算来逼近X,因此除2运算是必须使用的)然后采用除2运算逼近X, 从上述得知,除2运算是必须的

区别就是,是否要进行两次递增运算,然后进行除2运算,还是直接除2运算, 从数学运算可以得知(Y+1+1)/2=Y/2+1,需要三次运算,而Y/2+1只需要两次运算,从而得知,在第三种情况下,进行直接除2是永远比先递增然后除2要完美的

 

 

最后说一下,为什么不直接正向求解,原因就是这样,如果直接求解X到Y

那么首先由的情况的第一种X>Y,这个只能进行递增

第二个情况,X<Y,然后这种时候需要计算的情况就多了,首先如果Y是奇数,那么就可以得知最后一次运算不可能是X*2得到的,只可能是X-1,然后就可以吧题目换算成X到(Y-1),这个时候就进入第三种情况了

第三个情况,X<Y,并且Y是偶数,这种时候,X要最少次数达到Y的状态,那么还是一样的选择,因为Y是偶数,所以最后一次是*2运算,因此计算是(X-1)*2或者X*2【至于为什么不是(X-1-1)*2这些可以递归得到,因此不多列举】,首先也对结果进行求值,那么结果是2X-2【两次操作】和2X【一次操作】

那么似乎有可能结果刚刚好是2X-2的时候,X先-1然后*2优于2X  ?实际上,这种时候就需要看Y了,看看哪种方法能更快逼近X

最后发现,还是要看Y,那么为什么不直接从Y开始逆推?

 

最后上代码

python解法

class Solution(object):
    # 思路,主要有几种情况,第一,Y小于X,那么这种情况下,只能进行疯狂递减操作,需要进行X-Y次操作
    # 第二,Y>X,那么首先观察,Y是否为奇数,如果是奇数,那么只能Y先+1,如果是偶数,那么就可以直接Y除2,查看是够相近
    def brokenCalc(self, X, Y):
        """
        :type X: int
        :type Y: int
        :rtype: int
        """
        # 递归思路
        # if X == Y:
        #     return 0
        # if X > Y:
        #     return X - Y
        # if Y % 2 == 0:
        #     return 1 + self.brokenCalc(X,int(Y/2))
        # else:
        #     return 1 + self.brokenCalc(X,Y+1)
        # 循环思路
        allnum = 0
        while X != Y:
            if X > Y:
                allnum += (X - Y)
                break
            if Y % 2 == 0:
                Y /= 2
                allnum+=1
            else:
                Y += 1
                allnum+=1
        return int(allnum)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值