如何检查二进制数是否可被 3 整除

2025年3月17日 | 阅读11分钟

问题是检查给定的二进制数是否能被 3 整除,或者是否是 3 的倍数。

这个问题在编程界非常流行,并被亚马逊、微软、Adobe 等公司在软件工程面试中提问。

二进制数可以是字符串形式或整数形式。在进行实现之前,我们还需要注意这一点。

示例 1

示例 2

在本文中,我们将学习解决此问题的不同方法,并讨论检查二进制数是否是三的倍数的最佳方法。

方法 1 - 转换为十进制

最简单的方法是将二进制数转换为十进制等效数。然后检查它是否能被 3 整除。

将二进制数转换为十进制

  • 从右到左遍历数字。
  • 将每个数字乘以 2,2 的幂为其位置。
  • 对每次迭代的结果求和。

检查该数字是否能被 3 整除;如果能,则该二进制数也能被 3 整除。

下面是相同的 Python 实现

输出

Is binary1 = 11 divisible by 3? True
Is binary2 = 1100 divisible by 3? True
Is binary3 = 1011 divisible by 3? False

时间复杂度 = O(n): 其中 n 是二进制数中的位数。

空间复杂度 - O(1): 它使用常量空间。

方法 2 - 使用 DFA(确定性有限自动机) - 状态机方法

一种更有效的方法是设计一个模拟除法过程的 DFA。

状态机或 DFA 将有三个状态:0、1 和 2,分别表示二进制数除以三的余数。

DFA 的图示表示如下

How to Check if a Binary Number is Divisible by 3

我们将从初始状态 0 开始,并从左到右迭代二进制位,根据转换更新状态

  • 如果当前状态为 0
    • 如果数字为 0,状态保持为 0 - 转换:状态 0 -> 状态 0
    • 如果数字为 1,我们移动到下一个状态 1 - 转换:状态 0 -> 状态 1
  • 如果当前状态为 1
    • 如果数字为 0,我们移动到状态 2 - 转换:状态 1 -> 状态 2
    • 如果数字为 1,我们回到状态 0 - 转换:状态 1 -> 状态 0
  • 如果当前状态为 2
    • 如果数字为 1,我们循环到状态 2 - 转换:状态 2 -> 状态 2
    • 如果数字为 0,我们回到状态 1 - 转换:状态 2 -> 状态 1

遍历所有数字后,如果最终状态为 0,则二进制数能被三整除,我们返回 True。否则,返回 False。

下面是相同的 Python 实现

输出

Is binary1 = 11 divisible by 3? True
Is binary2 = 1100 divisible by 3? True
Is binary3 = 1011 divisible by 3? False

时间复杂度 = O(n): 其中 n 是二进制数中的位数。

空间复杂度 - O(1): 它使用常量空间用于状态变量。

但这种方法不是最有效的,也需要先前的自动机知识。

方法 3 - 位操作 - (|奇数位 - 偶数位|) 能被 3 整除

这是确定二进制数是否能被三整除的最有效且优雅的方法

我们将分别计算奇数位置和偶数位置的 1 的数量。

如果这些计数的差能被三整除,则二进制数能被三整除。

一般来说,二进制数 N 可以表示为

N = bn 2n-1+ bn-1 2n-2+ bn-22n-3+ … + b222 + b121 + b020

其中 bi 表示二进制位(0 或 1),n 表示 2 的最高次幂。

现在,让我们检查每个 2 的幂除以 3 的余数

我们可以观察到,随着 2 的幂增加,余数在 1 和 2 之间交替。

根据上述模式,表达式 (2^k) % 3 可以简化如下

因此,对于一个二进制数要能被 3 整除,偶数位置和奇数位置的 1 的数量之差必须能被 3 整除。

在十进制系统中,如果一个数字的各位数字之和能被三整除,那么这个数字也能被 3 整除。另一种方法是对于偶数位置的 1,我们计数为 2,对于奇数位置的 1,我们计数为 1

如果计数能被 3 整除。那么二进制数就能被 3 整除。

位操作的 Python 实现如下

在我们的方法中,我们分别计算偶数位置和奇数位置的 1 的数量,并检查它们的差是否能被 3 整除。如果能,则二进制数能被三整除。否则,不能整除。

输出

Is binary1 = 11 divisible by 3? True
Is binary2 = 1100 divisible by 3? True
Is binary3 = 1011 divisible by 3? False

说明

  • 在上面的示例中,我们从右到左(从最低有效位到最高有效位)遍历二进制数。
  • odd_position 最初设置为 True
    • 一旦我们在奇数位置,我们检查该数字是否为 '1'。如果为 '1',我们递增 ones_at_odd 1。
    • 然后,我们将 odd_position 设置为 False,表示下一个索引将是偶数。
  • 如果 odd_position 设置为 False,则表示我们在偶数索引处
    • 我们检查该数字是否为 '1'。如果为 '1',我们递增 ones_at_even 1。
    • 然后,我们将 odd_position 设置为 True,表示下一个索引将是奇数。
  • 循环完成后,我们计算偶数位置和奇数位置的 1 的数量之差 (ones_at_even - ones_at_odd)。
  • 最后,我们检查这个差是否能被 3 整除 ((ones_at_even - ones_at_odd) % 3 == 0)。
  • 如果差能被 3 整除,我们返回 True,表示二进制数能被三整除。否则,我们返回 False。

时间复杂度 = O(n), 其中 n 是二进制数中的位数。

空间复杂度 = O(1) 因为我们只需要几个变量来存储计数器。

最佳方法

  • 在讨论的方法中,位操作方法是检查二进制数是否能被三整除的最有效方法。
  • 这种方法易于理解,避免了转换为十进制,并直接对二进制数进行操作。

C++ 实现

输出

How to Check if a Binary Number is Divisible by 3

C 语言实现

输出

How to Check if a Binary Number is Divisible by 3

结论

我们可以使用各种方法来检查二进制数是否能被三整除。

  • 我们可以将二进制数转换为其十进制等效数,然后检查它是否能被 3 整除。
  • 另一种方法是设计一个模拟除法过程的 DFA。DFA 将有三个状态,0、1 和 2,表示除以 3 时的余数。如果我们最终停在状态 0。那么我们可以说该二进制数能被 3 整除。
  • 最有效的方法是确定奇数位置和偶数位置的 1 的数量之差。如果差能被三整除,则二进制数也能被 3 整除。

我们可以使用最后一种方法以线性时间复杂度解决问题。此外,这也是检查二进制数是否能被三整除的推荐方法。


下一主题股票买卖问题