【问题标题】:Maximum length of consecutive ones in binary representation二进制表示中连续的最大长度
【发布时间】:2020-07-19 12:25:14
【问题描述】:

试图在包括负数的二进制表示中找到最大长度。在以下代码中input_file 是一个文本文件,其中:

  • 第一行是包含样本整数的行数
  • 从第二行开始的每一行只有一个样本整数

一个示例文件:

4 - 样本数

3 - 样本

0 - ...

1 - ...

2 - ...

结果:2

任务:打印输入文件中所有样本整数中找到的最大数。找到需要 O(n) 时间并且只通过所有样本一次的解决方案。

如何修改解决方案以使用任意大小的负整数(或至少对于n ≤ 10000)?

更新:

据我了解,负数的二进制表示基于二进制补码 (https://en.wikipedia.org/wiki/Two's_complement)。所以,例如:

+3 -> 011

-3 -> 101

在一般情况下如何将整数转换为二进制字符串表示并考虑其符号?

def maxConsecutive(input): 
    return max(map(len,input.split('0'))) 

def max_len(input_file):
    max_len = 0
    with open(input_file) as file:
        first_line = file.readline()
        if not first_line:
            return 0
        k = int(first_line.strip()) # number of tests
        for i in range(k):
            line = file.readline().strip()
            n = int(line)
            xs = "{0:b}".format(n)
            n = maxConsecutive(xs)
            if n > max_len:
                max_len = n
    return max_len

print(max_len('input.txt'))

更新 2: 这是来自 Yandex 竞赛培训页面的第二个任务 Bhttps://contest.yandex.ru/contest/8458/enter/?lang=en

您需要在那里注册以测试您的解决方案。

到目前为止,这里给出的所有解决方案都在测试 9 中失败。

更新 3:通过所有 Yandex 测试的 Haskell 解决方案

import Control.Monad (replicateM)

onesCount :: [Char] -> Int
onesCount xs = onesCount' xs 0 0
    where
        onesCount' "" max curr 
            | max > curr = max 
            | otherwise  = curr
        onesCount' (x:xs) max curr
            | x == '1' = onesCount' xs max $ curr + 1 
            | curr > max = onesCount' xs curr 0 
            | otherwise = onesCount' xs max 0

getUserInputs :: IO [Char]
getUserInputs = do
    n <- read <$> getLine :: IO Int
    replicateM n $ head <$> getLine

main :: IO ()
main = do
    xs <- getUserInputs 
    print $ onesCount xs

【问题讨论】:

  • 我对 Haskell 不太熟悉,但似乎该函数希望每一行都已经表示为 1 和 0 的字符串。 oneCount 的签名接受一个字符数组(即一个字符串)并返回一个数字,该数字是字符串中最大连续的“1”字符。在该代码中,我看不到整数值在哪里转换为它的位表示。它似乎没有比max(map(len,bits.split("0")))
  • 谢谢,会查的!

标签: python algorithm binary


【解决方案1】:

对于负数,您要么必须决定字长(32 位、64 位……),要么将它们作为绝对值处理(即忽略符号),或者对每个值使用最小位数.

控制字长的一种简单方法是使用格式字符串。您可以通过将该值添加到与所选字长相对应的 2 次方来获得负位。这将为您提供正数和负数的适当位。

例如:

n = 123
f"{(1<<32)+n:032b}"[-32:]  --> '00000000000000000000000001111011'

n = -123
f"{(1<<32)+n:032b}"[-32:]  --> '11111111111111111111111110000101'

计算最长的连续 1 序列的处理只是字符串操作的问题:

如果您选择使用不同的字长来表示负数,您可以使用比正数的最小表示形式多一位。例如,-3 在正数时表示为两位('11'),因此至少需要 3 位才能表示为负数:'101'

n        = -123
wordSize = len(f"{abs(n):b}")+1
bits     = f"{(1<<wordSize)+n:0{wordSize}b}"[-wordSize:]
maxOnes  = max(map(len,bits.split("0")))

print(maxOnes) # 1   ('10000101')

【讨论】:

  • 谢谢,"{(1&lt;&lt;wordSize)+n:0{wordSize}b}" 表示法我很难理解,能否请您改写为format 表达式?谢谢!
  • "{0:0{1}b}".format((1&lt;&lt;wordSize)+n,wordSize) 诀窍是让第二个参数提供第一个参数的部分格式。
  • 谢谢!不幸的是,这个解决方案以及另一个解决方案都没有通过所有测试。请参阅更新 2。
  • 您能否在帖子中包含测试数据和预期结果,我无法登录链接的站点。
  • 在这个站点上,他们通过一系列测试运行您的代码。您所看到的只是通过的测试编号列表和失败的测试编号。他们不显示测试数据,所以你只能猜测哪里出了问题,然后再试一次。对于每个问题,您有 100 次尝试。在我给你的登录链接中,有一个注册 Yandex 竞赛的选项。不幸的是,没有其他方法可以做到这一点。另请参阅我在 Haskell 中通过所有 Yandex 测试的 Update 3 解决方案。
【解决方案2】:

假设

OP 想要二进制补码。

Python 的整数已经使用二进制补码,但是因为它们有 任意精度,负数的二进制表示 开始时会有一个无限的 1 字符串,很像正数 数字有一个无限的 0 字符串。因为这显然不可能 如图所示,它改为用减号表示。 reference

这会导致:

>>> bin(-5)
'-0b101'

因此,为了消除无限精度的影响,我们可以将 2 的补码显示为固定位数。在这里使用 16,因为 OP 提到数字是

>>> bin(-5 % (1<<16))            # Modulo 2^16
>> bin(-5 & 0b1111111111111111)  # 16-bit mask
'0b1111111111111011'

使用 2 的补码的示例

测试代码

result = []
for line in ['+3', '-3', '-25', '+35', '+1000', '-20000', '+10000']:
  n = int(line)
  xs = bin(n & 0b1111111111111011) # number in 16-bit 2's complement
  runs = maxConsecutive(xs)
  print(f"line: {line}, n: {n}, 2's complement: {xs}, max ones run: {runs}")
  result.append(runs)

print(f'Max run is {max(result)}')

测试输出

line: +3, n: 3, 2's complement binary: 0b11, max ones run: 2
line: -3, n: -3, 2's complement binary: 0b1111111111111101, max ones run: 14
line: -25, n: -25, 2's complement binary: 0b1111111111100111, max ones run: 11
line: +35, n: 35, 2's complement binary: 0b100011, max ones run: 2
line: +1000, n: 1000, 2's complement binary: 0b1111101000, max ones run: 5
line: -20000, n: -20000, 2's complement binary: 0b1011000111100000, max ones run: 4
line: +10000, n: 10000, 2's complement binary: 0b10011100010000, max ones run: 3
Max run is 14

代码

def maxConsecutive(input):
    return max(map(len,input[2:].split('0')))  # Skip 0b at beginning of each

def max_len(input_file):
    max_len_ = 0
    with open(input_file) as file:
        first_line = file.readline()
        if not first_line:
            return 0
        k = int(first_line.strip()) # number of tests
        for i in range(k):
            line = file.readline().strip()
            n = int(line)
            xs = bin(n & '0b1111111111111011') # number in 16-bit 2's complement
            n = maxConsecutive(xs)
            if n > max_len_:
                max_len_ = n
    return max_len_

代码简化 max_len

max_len 可以简化为:

def max_len(input_file):
  with open(input_file) as file:
    return max(maxConsecutive(bin(int(next(file).strip()), 0b1111111111111011)) for _ in range(int(next(file))))

【讨论】:

  • 谢谢!然而,您的解决方案没有考虑负数的二进制补码。请查看我的问题更新。
  • @dokondr-是的。请参阅我的更新答案示例。通过检查 input[0] 是否为符号来工作,即“-”。如果是这样,则使用 input[1:] 跳过。
  • maxConsecutive(+3) 应该返回 2,而 maxConsecutive(-3) 应该返回 1
  • @dokondr--对于 line = '+3',n = 3。然后我们有 xs = "{0:b}".format(n) 将 n 转换为以 2 为底的字符串。这将导致11。所以我们调用maxConsecutive('11') 得到2。对于line = '-3'``,n = -3, xs = -11. We call maxConsecutive('-11')` 也得到2。
  • 二进制补码是对二进制数的数学运算......它在计算中用作有符号数表示的一种方法。 N 位数的二进制补码定义为它相对于 2^N 的补码。例如,对于三位数字 010,二进制补码是 110,因为 010 + 110 = 1000。二进制补码是通过反转数字和加一来计算的。 二进制补码是计算机上表示有符号整数的最常用方法。对于 -3 的赞美是 101。所以 maxConsecutive 必须为 -3 返回 101,而对于其他负数的赞美
猜你喜欢
  • 2016-11-04
  • 2019-10-13
  • 2022-01-08
  • 1970-01-01
  • 2015-06-08
  • 2018-08-03
  • 1970-01-01
  • 2017-07-01
  • 2010-12-26
相关资源
最近更新 更多