• 算法题:李嘉诚保险柜密码问题


      据说,李嘉诚的保险柜密码是一个 8 位的数字。他经常更换密码,但换密码的规则很简单,每次都把密码的数字 * 3,如果有位数溢出,就把最前面的那个数字挪到整个数字末尾加起来 —— 比如 98765432 就会变成 98765432 * 3 = 296296296, 但是这有 9 位, 把最前面的 2 加到末尾, 变成 96296298, 就是新密码。现在我们偷到了李嘉诚的保险柜,而且我们知道他最初的密码是 00000001, 已经迭代了 n 次,求一个算法,可以在 O(log n) 的时间内算出密码。

    迭代分析第n次的密码计算公式:

    X0 = 0000 0001

    X1 = (3 * X0) % 108 + (3 * X0) / 108,显然,X1< 108

    X2 = (3 * X1) % 108 + (3 * X1) / 108

       = {3 * [(3 * X0) % 108 + (3 * X0) / 108]} % 10+ {3 * [(3 * X0) % 108 + (3 * X0) / 108]} / 108

         = {3 * [(3 * X0) % 108]} % 10+ {3 * [(3 * X0) / 108]}(显然其值<9) % 10

            + {3 * [(3 * X0) % 108 ]} / 10+ {3 * [(3 * X0) / 108]} / 108(显然其值趋于0)

         = (3* X0) % 10(由分配率得) + (32 * X0) / 10+ [(32 * X0) % 108 ] / 108(趋于0忽略) + 0

         = (3* X0) % 10 + (32 * X0) / 108

    X3 = (33 * X0) % 10 + (33 * X0) / 108

    以此类推可得:

    Xn = (3n * X0) % 10 + (3n * X0) / 108

    又因:X0 = 1,所以:Xn = 3n % 10 + 3n / 108

    关于计算3n

    1、简单处理的话可以n个3联乘,时间复杂度O(n),当n较大时比较耗时,此题暂时不考虑大数问题;

    2、当n为偶数时,3n=[3(n/2)]2,当n为奇数时,3n=3*{3[(n-1)/2]}2,时间复杂度O(log n),此为最优解法。

    Python实现如下:

    def g(x):
        return x % 100000000 + x // 100000000
    
    def f(x):
        if x == 1:
            return 3
        elif x % 2 == 0:
            return g(f(x / 2) * f(x / 2))
        elif x % 2 == 1:
            return g(f(1) * f(x - 1))
    
    if __name__ == '__main__':
        print(f(50))
    

    参考资料:

      大整数求余数的问题分析

      取模运算_运算规则_分配率——百度百科

  • 相关阅读:
    4
    把URL传递参数转变成自定义实体方法
    【转载】C#后台声明式验证,远离if验证
    判断访问浏览器版本
    用属性动画模仿展开菜单
    N个数随机相加得出固定值的排列组合
    css3--box-shadow
    学习仅仅是靠意志力吗
    cmd 输入php出错
    切图注意事项
  • 原文地址:https://www.cnblogs.com/gotodsp/p/5723743.html
Copyright © 2020-2023  润新知