Python:在整数的二进制表示中查找最长的二进制间隙

Posted

技术标签:

【中文标题】Python:在整数的二进制表示中查找最长的二进制间隙【英文标题】:Python: Find longest binary gap in binary representation of an integer number 【发布时间】:2018-08-03 17:32:02 【问题描述】:

我想知道我的实施是否有效。 我试图使用 python 找到该问题的最简单和低复杂度的解决方案。

def count_gap(x):
    """
        Perform Find the longest sequence of zeros between ones "gap" in binary representation of an integer

        Parameters
        ----------
        x : int
            input integer value

        Returns
        ----------
        max_gap : int
            the maximum gap length

    """
    try:
        # Convert int to binary
        b = "0:b".format(x)
        # Iterate from right to lift 
        # Start detecting gaps after fist "one"
        for i,j in enumerate(b[::-1]):
            if int(j) == 1:
                max_gap = max([len(i) for i in b[::-1][i:].split('1') if i])
                break
    except ValueError:
        print("Oops! no gap found")
        max_gap = 0
    return max_gap

让我知道你的意见。

【问题讨论】:

codility BinaryGap test 允许使用 18 种不同语言编写解决方案:C, C++, C#, Go, Java 8, Java 11, javascript, Kotlin, Lua, Objective-C, Pascal, php, Perl, Python, Ruby, Scala, Swift 4, Visual Basic。所以我认为没有任何理由将此问题仅限于 Python。 【参考方案1】:

我确实意识到简洁并不意味着可读性或效率。

但是,能够立即用口语阐明解决方案并在 Python 中实现它,这构成了我对时间的有效利用。

对于二进制间隙:嘿,让我们将 int 转换为二进制,去除尾随零,在 '1' 处拆分为列表,然后在列表中找到最长的元素并获取该元素的长度。

def binary_gap(N):
    return len(max(format(N, 'b').strip('0').split('1')))  

【讨论】:

超级好看:thumbsup: 这一班轮确实非常高效。但是我卡在了一个点上,strip 的功能是什么?我在不使用条带的情况下运行了该代码,它具有相同的输出。提前谢谢你。 根据定义,二进制间隙是“1 之间的零”,因此不应将尾随零视为二进制间隙。尝试使用 int 32(二进制为 100000)运行这两个版本。使用条带你得到 0(没有二进制间隙)没有条带你得到 5(这是不正确的,因为 1 之间没有 5 个零)。 如果您正在寻找性能:@Orenico 在他的答案中使用的 bin() 比 format(N, 'b') 快很多。 @quassy - 请定义“快一点”。使用 timeit 和 Python 3.8 进行的随意检查表明 format() 比 bin()[2:] 快一点。同样的随意检查也表明可以声称f"N:b"“快得多”。【参考方案2】:

您的实现将整数转换为以二为底的字符串,然后访问字符串中的每个字符。相反,您可以使用<<& 访问整数中的每一位。这样做将避免访问每个位两次(首先将其转换为字符串,然后检查结果字符串中是否为“1”)。它还将避免为字符串分配内存,然后为您检查的每个子字符串分配内存。

您可以通过访问 1

例如:

def max_gap(x):
    max_gap_length = 0
    current_gap_length = 0
    for i in range(x.bit_length()):
        if x & (1 << i):
            # Set, any gap is over.
            if current_gap_length > max_gap_length:
                max_gap_length = current_gap_length
            current_gap_length = 0
         else:
            # Not set, the gap widens.
            current_gap_length += 1
    # Gap might end at the end.
    if current_gap_length > max_gap_length:
        max_gap_length = current_gap_length
    return max_gap_length

【讨论】:

我建议使用int.bit_length 方法而不是ceil(log2(...)) 计算,以避免由于舍入导致的极端情况错误。 您说过您的实现将整数转换为以二为底的字符串,然后访问字符串中的每个字符,但这并不完全正确,因为我在检测到一个字符后中断然后我拆分。请您强调一下为什么您的实现在时间和内存复杂性方面应该更好。 你仍然需要访问每个角色。不然split怎么能找到合适的分割位置?它会访问每个字符,直到找到您提供的值。 嗨,Jean,您的代码比我提供的要慢得多。我将在答案中添加时间复杂度(作为运行时间测试代码)。 谢谢,让。一开始,我害怕在 *** 中发布我的代码(负 cmets),但您真的鼓励我继续前进(发布和优化)。祝你好运【参考方案3】:
def max_gap(N):
    xs = bin(N)[2:].strip('0').split('1')
    return max([len(x) for x in xs])

解释:

    前导零和尾随零对于二进制间隙查找都是多余的 因为它们不受两个 1 的限制(分别为左和右) 因此,第 1 步左右分条零 然后除以 1 得到所有 0'z 的序列 解决方法:0的子串最大长度

【讨论】:

欢迎来到 Stack Overflow!感谢您提供代码 sn-p,它可能会提供一些有限的即时帮助。通过描述为什么这是解决问题的好方法,正确的解释将极大地改进其long-term value,并使其对有其他类似问题的未来读者更有用。请编辑您的答案以添加一些解释,包括您所做的假设。【参考方案4】:

正如 cmets 中所建议的,itertools.groupby 可以有效地将可迭代的元素(如字符串)进行分组。你可以这样处理:

from itertools import groupby

def count_gap(x):
    b = "0:b".format(x)
    return max(len(list(v)) for k, v in groupby(b.strip("0")) if k == "0")

number = 123456
print(count_gap(number))

首先,我们从两端去除所有零,因为间隙必须在两端都有一个。然后itertools.groupby 将 1 和 0 组合在一起,我们将密钥(即“0”或“1”)与一个组一起提取(即,如果我们将其转换为列表,它看起来像“0000”或“11”)。接下来,如果 k 为零,我们收集每个组 v 的长度。并由此确定最大的数字,即零与零之间的最长间隙。

【讨论】:

【参考方案5】:

我认为当输入数字为 32 (100000) 时,接受的答案不起作用。这是我的解决方案:

def solution(N):
    res = 0
    st = -1
    for i in range(N.bit_length()):
        if N & (1 << i):
            if st != -1:
                res = max(res, i - st - 1)
            st = i

    return res

【讨论】:

这是***中评论答案的一部分。尽管代码是解释性的,但添加一些解释。 添加说明。【参考方案6】:
def solution(N):
    # write your code in Python 3.6
    count = 0
    gap_list=[]
    bin_var = format(N,"b")
    for bit in bin_var:
        if (bit =="1"):
            gap_list.append(count)
            count =0
        else:
            count +=1
    return max(gap_list)

【讨论】:

【参考方案7】:

这是我的解决方案:

def solution(N):
    num = binary = format(N, "06b")
    char = str(num)
    find=False
    result, conteur=0, 0

    for c in char:
        if c=='1' and not find:
            find = True
            
        if find and c=='0':
            conteur+=1

        if c=='1':
            if result<conteur:
                result=conteur
            conteur=0

    return result

【讨论】:

【参考方案8】:

这也有效:

def binary_gap(n):
    max_gap = 0
    current_gap = 0

    # Skip the tailing zero(s)
    while n > 0 and n % 2 == 0:
        n //= 2

    while n > 0:
        remainder = n % 2
        if remainder == 0:
            # Inside a gap
            current_gap += 1
        else:
            # Gap ends
            if current_gap != 0:
                max_gap = max(current_gap, max_gap)
                current_gap = 0
        n //= 2

    return max_gap

【讨论】:

【参考方案9】:

老问题,但我会使用生成器解决它。

from itertools import dropwhile

# a generator that returns binary 
# representation of the input
def getBinary(N):
    while N:
        yield N%2
        N //= 2

def longestGap(N):
    longestGap = 0
    currentGap = 0

    # we want to discard the initial 0's in the binary
    # representation of the input
    for i in dropwhile(lambda x: not x, getBinary(N)):
        if i:
            # a new gap is found. Compare to the maximum
            longestGap = max(currentGap, longestGap)
            currentGap = 0
        else:
            # extend the previous gap or start a new one
            currentGap+=1

    return longestGap

【讨论】:

【参考方案10】:

可以使用 strip() 和 split() 函数来完成: 步骤:

    转换为二进制(去掉前两个字符) 将int转换为字符串 分别删除尾随和开始的 0 和 1 从字符串中用 1 拆分,找到字符串的子序列 求最长子串的长度

第二个strip('1')不是强制性的,但它会减少要检查的案例并提高时间复杂度 最坏情况T

def solution(N):
    return len(max(bin(N)[2:].strip('0').strip('1').split('1')))

【讨论】:

【参考方案11】:

使用位移运算符的解决方案 (100%)。基本上复杂度是 O(N)。

def solution(N):
    # write your code in Python 3.6
    meet_one = False
    count = 0
    keep = []
    while N:
        if meet_one and N & 1 == 0:
            count+=1
        
        if  N & 1:
            meet_one = True
            keep.append(count)
            count = 0
        N >>=1

    return max(keep)

【讨论】:

【参考方案12】:
def solution(N):
# write your code in Python 3.6

    iterable_N = "0:b".format(N)
    max_gap = 0
    gap_positions = []
    for index, item in enumerate(iterable_N):
        if item == "1":
            if len(gap_positions) > 0:
               if (index - gap_positions[-1]) > max_gap:
                    max_gap = index - gap_positions[-1]
            gap_positions.append(index)
    max_gap -= 1 
    return max_gap if max_gap >= 0 else 0

【讨论】:

【参考方案13】:

这也有效:

def solution(N):
    bin_num = str(bin(N)[2:])
    list1 = bin_num.split('1')
    max_gap =0
    if bin_num.endswith('0'):
        len1 = len(list1) - 1
    else:
        len1 = len(list1)
    if len1 != 0:
        for i in range(len1):
            if max_gap < len(list1[i]):
                max_gap = len(list1[i])
    return max_gap

【讨论】:

【参考方案14】:
def solution(number):

    bits = [int(digit) for digit in bin(number)[2:]]
    occurences = [i for i, bit in enumerate(bits) if(bit==1)]
    res = [occurences[counter+1]-a-1 for counter, a in enumerate(occurences) if(counter+1 < len(occurences))]

    if(not res):
        print("Gap: 0")
    else:
        print("Gap: ", max(res))

number = 1042
solution(number)

【讨论】:

【参考方案15】:

这行得通

def solution(number):
    # convert number to binary then strip trailing zeroes
    binary = ("0:b".format(number)).strip("0")
    longest_gap = 0
    current_gap = 0
    for c in binary:
        if c is "0":
           current_gap = current_gap + 1
        else:
           current_gap = 0

        if current_gap > longest_gap:
           longest_gap = current_gap 


    return longest_gap

【讨论】:

【参考方案16】:
def max_gap(N):
    bin = '0:b'.format(N)
    binary_gap = []
    bin_list = [bin[i:i+1] for i in range(0, len(bin), 1)] 

    for i in range(len(bin_list)):
        if (bin_list[i] == '1'):
            # print(i)
            # print(bin_list[i])
            # print(binary_gap)
            gap = []
            for j in range(len(bin_list[i+1:])):
                # print(j)
                # print(bin_list[j])
                if(bin_list[i+j+1]=='1'):
                    binary_gap.append(j)
                    # print(j)
                    # print(bin_list[j])
                    # print(binary_gap)
                    break
                elif(bin_list[i+j+1]=='0'):
                    # print(i+j+1)
                    # print(bin_list[j])
                    # print(binary_gap)
                    continue
                else:
                    # print(i+j+1)
                    # print(bin_list[i+j])
                    # print(binary_gap)
                    break
        else:
            # print(i)
            # print(bin_list[i])
            # print(binary_gap)
            binary_gap.append(0)


    return max(binary_gap)
    pass

【讨论】:

你应该edit你的答案添加一个minimal reproducible example来证明问题。【参考方案17】:
def find(s, ch):
    return [i for i, ltr in enumerate(s) if ltr == ch]

def solution(N):
    get_bin = lambda x: format(x, 'b')
    binary_num = get_bin(N)
    print(binary_num)
    binary_str = str(binary_num)
    list_1s = find(binary_str,'1')
    diffmax = 0
    for i in range(len(list_1s)-1):
        if len(list_1s)<1:
            diffmax = 0
            break
        else:
            diff = list_1s[i+1] - list_1s[i] - 1
            if diff > diffmax:
                diffmax = diff
    return diffmax
    pass

【讨论】:

你能解释一下你的代码吗?不这样做就删除代码可能没有那么有用。【参考方案18】:
def solution(N: int) -> int:
    binary = bin(N)[2:]
    longest_gap = 0
    gap = 0
    for char in binary:
        if char == '0':
            gap += 1
        else:
            if gap > longest_gap:
                longest_gap = gap
            gap = 0
    return longest_gap

【讨论】:

请解释为什么你的答案比其他人好。这将有助于人们从您的回答中学习。【参考方案19】:

这是一个使用迭代器和生成器的解决方案,它们将处理边缘情况,例如数字 32 (100000) 的二进制间隙为 0,0 的二进制间隙为 0。它不会创建列表,而是依赖于迭代并一次一步处理位串的元素,以获得高效的内存解决方案。

def solution(N):
    def counter(n):
        count = 0
        preceeding_one = False
        for x in reversed(bin(n).lstrip('0b')):
            x = int(x)
            if x == 1:
                count = 0
                preceeding_one = True
                yield count
            if preceeding_one and x == 0:
                count += 1
                yield count
        yield count
    return(max(counter(N)))

【讨论】:

【参考方案20】:

这里还有一个似乎很容易理解的。

def count_gap(x):
     binary_str = list(bin(x)[2:].strip('0'))
     max_gap = 0 
     n = len(binary_str)
     pivot_point = 0

     for i in range(pivot_point, n):
         zeros = 0
         for j in range(i + 1, n):
              if binary_str[j] == '0':
                   zeros += 1 
              else:
                   pivot_point = j
                   break

         max_gap = max(max_gap, zeros)

     return max_gap

【讨论】:

【参考方案21】:

这真的很老了,我知道。但这是我的:

def solution(N):
    gap_list = [len(gap) for gap in bin(N)[2:].strip("0").split("1") if gap != ""]
    
    return max(gap_list) if gap_list else 0

【讨论】:

【参考方案22】:

这是另一个有效的解决方案。希望它可以帮助你。您只需要在函数中传递任意数字,它将返回最长的二进制间隙。

def LongestBinaryGap(num):

n = int(num/2)
bin_arr = []

for i in range(0,n):
    if i == 0:
        n1 = int(num/2)
        bin_arr.append(num%2)
    else:
        bin_arr.append(n1%2)
        n1 = int(n1/2)

        if n1 == 0:
            break

print(bin_arr)
result = ""
count = 0
count_arr = []

for i in bin_arr:
    if result == "found":
        if i == 0:
            count += 1
        else:
            if count > 0:
                count_arr.append(count)
                count = 0
    if i == 1:
        result = 'found'
    else:
        pass

if len(count_arr) == 0:
    return 0
else:
    return max(count_arr)

print(LongestBinaryGap(1130))  # Here you can pass any number.

【讨论】:

【参考方案23】:

我在 python 3.6 中的代码得分 100 获取二进制数..获取1的位置 得到 1.. 之间的 abs 差异对它进行排序

 S = bin(num).replace("0b", "")
          res = [int(x) for x in str(S)]
          print(res)
          if res.count(1) < 2 or res.count(0) < 1:
              print("its has no binary gap")
          else: 
            positionof1 = [i for i,x in enumerate(res) if x==1]
            print(positionof1)
            differnce = [abs(j-i) for i,j in zip(positionof1, positionof1[1:])]
            differnce[:] = [differnce - 1 for differnce in differnce]
            differnce.sort()
            print(differnce[-1])

【讨论】:

请在您的回答中提供更多详细信息。正如目前所写的那样,很难理解您的解决方案。【参考方案24】:
def solution(N):
    return len(max(bin(N).strip('0').split('1')[1:]))

【讨论】:

与此处提供的其他解决方案相比,这有什么好处吗?请edit解释。【参考方案25】:
def solution(N):
    maksimum = 0 
    zeros_list = str(N).split('1')
    if zeros_list[-1] != "" :
        zeros_list.pop()
        
    for item in zeros_list :
        if  len(item) > maksimum :
            maksimum = len(item)
    return(maksimum)

【讨论】:

【参考方案26】:
def solution(N):
    # Convert the number to bin 
    br = bin(N).split('b')[1]
    sunya=[]
    groupvalues=[]
    for i in br:
        count = i
        if int(count) == 1:
            groupvalues.append(len(sunya))
            sunya=[]
        if int(count) == 0:
            sunya.append('count') 

    return max(groupvalues)

【讨论】:

【参考方案27】:
def solution(N):
    bin_num = str(bin(N)[2:])
    bin_num = bin_num.rstrip('0')
    bin_num = bin_num.lstrip('0')
    list1 = bin_num.split('1')
    max_gap = 0

    for i in range(len(list1)):
        if len(list1[i]) > max_gap:
            max_gap = len(list1[i])

    return (max_gap)

【讨论】:

这适用于任何“二进制间隙”第 1 课代码 虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。 您的代码甚至没有运行,因为缺少缩进。请解决这个问题! @hellow,我在发帖时遇到了问题。代码工作得很好。 那么请阅读***.com/editing-help和***.com/help/how-to-answer。有很多帮助可以帮助您正确格式化您的答案,所以请不要以此为借口;)(在我参加一些驾驶课程之前,我不开车。那(几乎)是一样的。阅读先上说明,然后发布)

以上是关于Python:在整数的二进制表示中查找最长的二进制间隙的主要内容,如果未能解决你的问题,请参考以下文章

查找堆栈中最长的字符序列

Java题目训练——查找输入整数二进制中1的个数和手套

2017年中兴武汉秋招在线编程第二题

python:求整数的二进制表示

查找“n”个二进制字符串中最长的公共子串的长度

二进制中1的个数