计算步数达到 0 的函数

a function to count the step reaching 0

给定一个二进制数,我需要编写一个函数来计算达到零的总步数。规则是:

例如,“1110”(14)需要迭代六次才能变成0:

我想出了一个简单的计算解决方案,但是这个算法无法处理非常大的数字。

def test(x):
    a = int(x,2)
    steps = 0
    while a != 0:
        if a % 2 == 0:
            a = a // 2  
        else:
            a = a - 1
        steps += 1
    return steps
test("1000")
Out[65]: 4

test("101")
Out[66]: 4

test("001")
Out[67]: 1

test("0010010001")
Out[68]: 10

test("001001")
Out[69]: 5

我需要知道的:如何避免进行计算并拥有快速/可以处理大数的算法?

您的算法对奇数不正确。你只在数字为偶数时才除法,这不是你描述的 "steps."

你想要

def test(x, 2):
x_int = int(x)
steps = 0
while x_int <= 0:
    x_int //= 2
    x -= 1
    steps += 1

你应该澄清你的算法,因为你描述它的方式,你不能保证所有输入都收敛到 0。您描述的方式是奇数的无限循环。只需尝试 1:

#test(1)
1 // 2 = 0
0 - 1 = -1
...

现在你永远不会达到 0,这就是为什么你应该检查 x_int <= 0。

我建议你重新考虑一下你为什么要这么做。我相当确定您甚至不需要迭代算法来知道需要多少 "steps",应该只需要一个数学公式即可。

您也可以使用递归方法:

def stepsToZero(N):
    return N if N < 2 else 2 + stepsToZero(N//2-1)

这将使您得到最多 N = 2**993(这是一个相当大的数字)的结果,并且函数非常简洁(恕我直言,更优雅)。

运行 更快的方法是用数学方法解决这个问题

例如:

import math
def steps2Zero(N):
    if N < 2: return N
    d = int(math.log(N+2,2))-1
    s = int(N >= 3*2**d-2)
    return 2*d+s

请注意,对于 N=2^900,数学求解比递归快一百倍。另一方面,递归函数的响应时间不到一秒,而且可读性更高。因此,根据它的使用方式和大小,性能考虑可能毫无意义

假设您的代码是正确的并且规则是:

  • 测试(0) = 0
  • test(n) = 1 + test(n / 2) 如果 n 是偶数;
    1 + test(n − 1) 否则

需要注意的重要一点是:

  • 偶数以二进制0结尾
  • 除以 2 会删除末尾的 0(除此之外什么都没有)
  • 奇数以二进制1结尾
  • 减 1 将最后一个 1 变成 0(除此之外别无其他)

所以除了第一个之外,每1位增加2步,每一个有效的0位增加1步。这意味着对于以 1 开头的输入,您可以这样写:

def test(x):
    return x.count('1') + len(x) - 1

现在您只需要考虑前导零,或者如果前导零不可能,则只需考虑 "0" 的特定情况。

我今天在编码测试中遇到了这个问题,我有 40 分钟的时间来完成测试。不幸的是,我只是在计时器达到限制后才想出一个好的解决方案。

你不需要计算除法和减法(!)。你可以遍历S的字符,如果字符是1,需要两步, 如果字符是0, 只需要一步。

  • 末尾有1就减1
  • 如果末尾有0,除以2,数字会右移
  • 第一个字符异常(S[0])

解决方法如下:

def iterate_string(S: str):
    acc = 0
    for c in S:
        if c == "0":
            acc += 1
        else:
            acc += 2
    acc -= 1 # the very first 1 is only + 1, thus - 1
    return acc

举个例子:

  1. 1001 (17) - 1 = 1000 (16)
  2. 1000 (16) / 2 = 100 (8)
  3. 100 (8) / 2 = 10 (4)
  4. 10 (4) / 2 = 1
  5. 1 - 1 = 0
# First digit, requires two steps:
   |
1001

# Second digit, requires one step:
  |
1001

# Third digit, requires one step:
 |
1001

# S[0] is 1, but requires only one step:
|
1001

=> total of 5 steps:

0:  1001    # (-1)
1:  1000    # (/2)
2:   100    # (/2)
3:    10    # (/2)
4:     1    # (-1)
5:     0

祝下一个面临同样挑战的人好运! :)

这是无法处理大数字的幼稚解决方案:

def do_calculations(S: str):
    decimal_value = int(S, 2)
    iterations = 0
    while decimal_value > 0:
        if decimal_value % 2 == 1:
            decimal_value = decimal_value - 1
        else:
            decimal_value = decimal_value / 2
        iterations += 1
    return iterations