根据Python中的给定条件最小化n的最快方法

时间:2019-04-26 13:36:43

标签: python optimization bitwise-operators

如何使以下代码更快?输入是一个二进制字符串,我将其转换为数字。可能我需要使用二进制字符串而不是数字?该算法只能将其除以2或从输入中减去1。我尝试了下面的代码,它不够快。

我尝试了以下方法:

 holder.addlinetxt.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            JSONObject jsonObject = new JSONObject();
            try {

                jsonObject.put("name", "");
                Gson gson = new Gson();
                GrabAndGoSubLabelsModel addGoGrabLineModal = gson.fromJson(String.valueOf(jsonObject), GrabAndGoSubLabelsModel.class);
                grabAndGoSubLabelsModels.add(addGoGrabLineModal);
                addGoGrabLineBackendAdapter.notifyDataSetChanged();
                holder.addlineRecyclerview.setAdapter(addGoGrabLineBackendAdapter);
            } catch (JSONException e) {
            }
        }
    });

它的速度必须是此速度的两倍:

def steps_to_zero(n) : 

    n=int(n,2)
    count = 0
    while n > 0:
        if n % 2 == 0:            
            n = n // 2
        else:  
            n = n - 1

        count += 1
    return (count)

2 个答案:

答案 0 :(得分:5)

您提出的代码与给定的代码完全相同。 您要研究的主要要加快速度的方法是摆脱昂贵的if n % 2 == 0测试。

解决方案是,您可以在比特级上推理此问题,而不必进行任何蛮力计算。

对于普通情况n=0,我们得到count=0。对于下一个更简单的情况n=1,我们只需要减去1,就得出count=1

在所有其他情况下,我们要处理更长的二进制数。如果该数字的最后一位是0,我们可以除以2,使我们的二进制数字短一位:

...x0 / 2 = ...x  # 1 step for 1 digit shorter

否则我们必须先减去1,然后才能除以2。

...x1 - 1 = ...x0
...x0 / 2 = ...x   # 2 steps for 1 digit shorter

换句话说:对于最左边的1,我们需要1个运算,对于所有数字,如果它是0,则需要1;如果是1,则需要2。

这意味着您可以简单地通过计算字符串中1的数量来计算该值:

def steps_to_zero(n):
    n = n.lstrip('0')            # remove leading zeroes if they occur
    divisions = len(n) - 1       # don't have to divide for the left-most 1
    subtractions = n.count('1')  # each 1 needs a subtraction to become a 0
    return divisions + subtractions

% 2.count('1')之间的时间比较平均在0-10,000之间:

# % 2
$ python3 -m timeit -s "x=list(range(10000))" "[y%2 for y in x]"
1000 loops, best of 3: 277 usec per loop

# .count('1')
$ python3 -m timeit -s "x=[bin(i) for i in range(10000)]" "[y.count('1') for y in x]"
1000 loops, best of 3: 1.35 msec per loop

尽管每次执行.count('1')%2慢约5倍,.count('1')只需要执行一次,而%2必须执行log2(n)次。这使.count('1')的{​​{1}}处理速度更快。

答案 1 :(得分:4)

与其将字符串转换为数字并执行昂贵的除法和模运算,不如简单地一点一点地处理它。对于除最左边的每个1位,您将需要两个步骤(减法和除法),对于每个0位,您将需要一个步骤(除法):

def steps_to_zero(n):
    count = 0
    for x in n.lstrip('0'):
        if x == '1':
            count += 2
        else:
            count += 1
    return count - 1

或者,如果您喜欢单线:

def steps_to_zero(n):
    return sum((x == '1') + 1 for x in n.lstrip('0')) - 1