伴学笔记:解决二进制数能否被 5 整除的问题

144 阅读3分钟

一、问题分析

在这道题中,我们的任务是给定一个二进制数组 nums,并计算每个从 nums[0]nums[i](即前 i+1 位组成的二进制数)所表示的数,判断这个二进制数是否能被 5 整除。对于每个 i,我们需要返回一个布尔值,表示该二进制数是否能够被 5 整除。

例如:

  • 输入:nums = [0, 1, 1]

    • x0 = 0,可以被 5 整除,返回 True
    • x1 = 1,不能被 5 整除,返回 False
    • x2 = 3,不能被 5 整除,返回 False
    • 最终返回 [True, False, False]
  • 输入:nums = [1, 0, 1, 1, 0]

    • x0 = 1,不能被 5 整除,返回 False
    • x1 = 2,不能被 5 整除,返回 False
    • x2 = 5,可以被 5 整除,返回 True
    • x3 = 10,不能被 5 整除,返回 False
    • x4 = 20,不能被 5 整除,返回 False
    • 最终返回 [False, False, True, False, False]

二、关键思想

为了判断每个位置 i 对应的二进制数是否能被 5 整除,我们首先需要构造出从 nums[0]nums[i] 所表示的二进制数。构建这些二进制数时,我们可以利用一个数学技巧,即 左移加法

具体来说,给定 xi 表示从 nums[0]nums[i] 的二进制数:

  • x0 = nums[0]
  • x1 = (x0 * 2 + nums[1])
  • x2 = (x1 * 2 + nums[2])
  • ...

这样每次可以通过将当前的数左移一位(乘以 2)然后加上当前位的数,来更新二进制数。

此外,由于我们关心的是是否能被 5 整除,我们可以 对 5 取余 来判断。这样不仅能避免构造的数过大,还能直接知道该数是否能被 5 整除。

三、实现思路

  1. 初始化变量

    • xi:当前的二进制数,初始为 0
    • answer:存储每个 xi 是否能被 5 整除的布尔值列表。
  2. 遍历输入数组 nums

    • 对于每个元素 num,更新当前二进制数 xi = (xi * 2 + num) % 5,即左移一位并加上当前元素。
    • 判断 xi == 0,如果为 True,说明该二进制数能被 5 整除,将 True 加入结果列表 answer;否则加入 False
  3. 返回结果

    • 遍历完所有元素后,返回布尔值列表 answer

四、代码实现

def solution(nums: list) -> list:
    xi = 0  # 初始化 xi 为 0
    answer = []  # 用于存储每个 xi 是否能被 5 整除的结果
    
    for num in nums:
        xi = (xi * 2 + num) % 5  # 通过左移并加上当前位 num,且对 5 取余
        answer.append(xi == 0)  # 如果 xi 能被 5 整除,结果为 True,否则为 False
    
    return answer

# 测试用例
if __name__ == '__main__':
    print(solution(nums=[0, 1, 1]) == [True, False, False])
    print(solution(nums=[1, 0, 1, 1, 0]) == [False, False, True, False, False])
    print(solution(nums=[1, 1, 1]) == [False, False, False])

五、代码解析

  1. xi = 0

    • 我们从 xi = 0 开始,表示当前的二进制数为 0。
  2. xi = (xi * 2 + num) % 5

    • 对每个二进制位,我们通过左移并加上当前位的方式构造出新的二进制数。
    • 由于我们只关心 xi 是否能被 5 整除,因此每次更新后都对 5 进行取余。
  3. answer.append(xi == 0)

    • 如果当前的二进制数 xi 能被 5 整除(即 xi % 5 == 0),就将 True 加入 answer,否则加入 False
  4. 返回结果

    • 最后返回 answer 列表,即每个位置是否能被 5 整除的结果。

六、时间复杂度分析

  • 遍历一次 nums 数组,每次操作的时间复杂度为常数时间 O(1)。
  • 因此,整个算法的时间复杂度是 O(n),其中 nnums 数组的长度。

七、空间复杂度分析

  • 我们使用了一个 answer 列表来存储结果,因此空间复杂度为 O(n),其中 nnums 数组的长度。

八、总结

这道题考察了如何通过左移和加法来逐步构造一个二进制数,并判断该数是否能被 5 整除。通过 模运算 来避免数值过大,提高了算法的效率。通过此题,我进一步理解了如何在循环中处理动态变化的数值,并优化了计算过程,使得问题得以高效解决。