AI 刷题 185.小E的按位与挑战题解 | 豆包MarsCode AI刷题

76 阅读3分钟

小E的按位与挑战

问题描述

小E的挑战是从一个长度为 n 的数组中选择一个或多个数。她需要确保选择的这些数的按位与(AND)结果不为零,并且这个结果可以被 (2^m) 整除。目标是让整数 (m) 尽可能大。

按位与运算

按位与运算是位操作中最基本的操作之一。它对每一位二进制数进行比较,当且仅当两位均为1时,结果才为1,这使得按位与运算的结果可以体现出两个数所有相同的位数。

示例

为了更好地理解这个问题的实现,我们可以来看几个示例:

  • 示例1:

    • 输入:n = 5, a = [1, 2, 3, 20, 28]
    • 输出:2 (选择 20 和 28,它们按位与的结果为 20,可整除 (2^2))
  • 示例2:

    • 输入:n = 4, a = [16, 8, 4, 2]
    • 输出:4 (所有数的按位与结果为 0,但单独选择 16 则可整除 (2^4))
  • 示例3:

    • 输入:n = 6, a = [7, 14, 28, 56, 112, 224]
    • 输出:5 (任意从中选择的组合可以得到 (m=5))

解题思路

  1. 尾部零的计算:要判断一个数 (y) 能够被 (2^m) 整除的程度,与其尾部的零数量有关。尾部零的数量就是这个数可以被2的幂次方整除的最大值。

  2. 选择合适的数:我们需要从数组中计算每个数的尾部零数量,找出其中的最大值。这个最大值就是可以得到的 (m)。

  3. 确保按位与结果不为0:在计算尾部零的过程中,如果尾部零的最大数量大于0,表示有选中的数能够使按位与操作的结果不为0。

处理边界情况

对于数组中的数,如果全部都是奇数,按位与的结果必然不为零,但 (m) 的值将为0。在这种情况下,我们需要确保最终结果的合理性。

解题代码

以下是实现上述思路的 Python 代码:

def solution(n: int, a: list) -> int:
    def trailing_zeros(x):
        # 计算一个数的尾部零数
        count = 0
        while x % 2 == 0:
            x //= 2
            count += 1
        return count

    # 初始化最大尾部零的数量
    max_zeros = 0
    for num in a:
        # 计算每个数的尾部零数量并找出最大值
        max_zeros = max(max_zeros, trailing_zeros(num))

    return max_zeros

if __name__ == '__main__':
    # 测试用例
    print(solution(5, [1, 2, 3, 20, 28]) == 2)  # 输出 2
    print(solution(4, [16, 8, 4, 2]) == 4)      # 输出 4
    print(solution(6, [7, 14, 28, 56, 112, 224]) == 5)  # 输出 5
    print(solution(2, [10, 9]) == 1)  # 输出 1 (10有1个尾部0)

解题思路详细解析

尾部零的计算

计算一个数的尾部零数量可以通过不断将数除以2直到它不能再被整除。例如,对于一个数字 12

  • 12 除以 2 = 6(尾部零计数 = 1)
  • 6 除以 2 = 3(尾部零计数 = 2)
  • 3 无法被 2 整除(循环结束)

最后的计数就是这个数字的尾部零数量。

主逻辑

主逻辑在于通过遍历数组,使用 trailing_zeros 函数来计算每个数的尾部零数量,并同时更新 max_zeros,可以在O(n)的时间内完成这一计算。通过这样的处理,结果不仅能保证正确性,也能确保效率。

性能和复杂度分析

  1. 时间复杂度:O(n),其中n是数组的长度。每个数字只需O(log x)的时间来看其能被多少次2整除,所有数的复杂度可以归约为线性的。

  2. 空间复杂度:O(1),仅使用了固定数量的额外空间存储中间值。

总结思考

通过解决这个问题,我对按位与操作和尾部零的理解有了更加深入的认识。数字的底层表示形式往往能提供很多信息,而通过简单的位操作,我们可以有效地解决相对复杂的问题。