Invert Actual Bits of a Number in Java

2025年5月8日 | 阅读 7 分钟

在 Java 中,反转数字的位数意味着将每个位从 0 翻转为 1,反之亦然。这可以通过按位非 (~) 运算符来实现。它常用于二进制操作和按位运算等任务,提供了一种翻转位模式的简单方法。

输入: 5 (二进制:0101)

输出: -6 (二进制:1010)

解释

当反转 5 的位数时,二进制表示 0101 变为 1010。在 Java 中,这种翻转还会改变符号位,从而导致负数。由于有符号整数使用的补码表示,二进制 1010 在十进制中对应于 -6。

按位反转方法

Java 中按位反转的特性

  • 简洁性: 按位反转是一种直接的操作,可以翻转数字的每一位。它易于实现,特别是使用内置的 按位 非运算符 (~) 时。
  • 高效性: 该操作以恒定时间 (O(1)) 执行,使其非常高效。它直接修改数字的所有位,而无需考虑数字的大小。
  • 平台独立性: 按位操作(包括反转)在 Java 中跨平台都能一致工作,因为该语言在不同系统上以相同的方式处理二进制表示。
  • 固定位宽: Java 的整数类型 (int) 始终为 32 位。因此,在执行按位反转时,结果始终是 32 位,并且该操作仅限于该范围。

算法

步骤 1:输入数字: 该过程首先接受或提供一个您想反转其位数的 整数 值。此数字可以是十进制格式,因为 Java 以此格式处理整数。

步骤 2:理解二进制表示: 计算机中的每个数字都以二进制表示。您可以将数字视为一系列位(0 和 1)。如果您直接处理二进制数字,可以手动表示它们,但 Java 会在后台自动处理。

步骤 2.1:确定数字的范围: 在处理按位操作时,理解数字的范围至关重要。Java 的 int 类型使用 32 位,可以表示从 -231 到 231 - 1 的值。范围有助于理解数字的二进制大小以及反转将如何影响它,尤其是在符号翻转和潜在溢出方面。

步骤 3:应用按位非运算符: 反转位的核心操作是按位非运算符 (~)。当您将此运算符应用于一个数字时:数字中的每个 0 都变为 1。每个 1 都变为 0。本质上,您正在翻转所有位。

步骤 4:考虑符号位: 在有符号整数(如 Java 使用的整数)中,最高有效位(最左边的位)指示数字是正数还是负数。翻转位时,也会翻转此符号位。

  • 如果原始数字是正数,翻转位可能会将符号变为负数。
  • 如果原始数字是负数,翻转位可能会使其变为正数。

步骤 5:解释结果: 反转位后,我们得到一个新数字。新数字表示原始数字的二进制补码。如果符号位已被翻转,结果可能是负数。

步骤 5.1:考虑补码表示: 在解释结果时,重要的是要记住 Java 使用补码表示法来表示有符号整数。

这意味着最高有效位决定了数字的符号。如果反转的数字是负数,Java 将使用补码自动解释它,从而得到正确的负值。

步骤 6:返回或显示结果: 最后,通常会返回或显示结果。如果您使用的是 Java,结果将自动从其二进制形式转换为十进制数字,您将看到反转位的输出。

输出

 
Inverted bits of 5 is: -6   

复杂度分析

时间复杂度

反转数字位的时间复杂度为 O(1)。这是因为按位非操作以恒定时间工作,与数字的大小无关。它只是翻转数字的每一位,并且此过程独立于数字的值或大小。

空间复杂度

反转数字位的空间复杂度为 O(1)。该操作仅需要恒定的空间量,因为它会就地修改数字,而无需与输入大小成比例的额外内存。仅使用一个变量来存储结果。

优点

  • 简洁性: 按位非 (~) 运算符使代码干净且易于实现。反转所有位只需一行代码。
  • 效率: 由于它直接翻转所有位,因此它是一种高度高效的操作,具有恒定时间复杂度 (O(1))。
  • 代码量少: 所需代码量最少,易于阅读、维护和调试。
  • Java 内置支持: Java 原生支持按位操作,从而减少了手动实现和复杂性的需求。

手动位操作方法

算法

步骤 1:输入数字: 第一步是获取要反转其位的数字。此数字以整数形式提供,Java 将其视为 32 位有符号整数。

步骤 2:初始化结果变量: 创建一个变量来存储反转位后的结果。从 0 开始。此变量将在翻转原始数字的每一位后累积新位。

步骤 2.1:确定位数: 由于 Java 使用 32 位整数,因此您知道循环将运行 32 次以处理数字的每一位。

步骤 3:循环遍历每一位: 使用循环处理数字的每一位。循环将从最低有效位(最右边的位)迭代到最高有效位(最左边的位)。对于每一位

向右移动数字 i 位。应用按位 AND (& 1) 来提取当前位。

步骤 3.1:跟踪当前位的位置: 随着循环的进行,请跟踪数字中当前的位位置。这对于将每一位反转后正确移位并放置到结果变量中至关重要。位位置由循环计数器 i 确定,i 从 0(最低有效位)开始,一直到 31(最重要的位)。它确保位操作从右到左正确进行。

步骤 4:反转位: 提取位后,将其翻转。如果位是 0,则将其更改为 1;如果位是 1,则将其更改为 0。这是通过从 1 中减去当前位来完成的。

步骤 5:在结果中设置位: 位反转后,将其移回正确的位置,并使用按位 OR (|) 将其设置到结果变量中。这确保了新的反转位被正确放置。

步骤 6:对所有位重复: 对所有 32 位重复此过程。循环将处理每一位,反转它,并将其设置到结果变量中。

步骤 6.1:处理溢出或边缘情况: 在某些情况下,可能需要检查结果是否溢出或是否存在边缘情况,尤其是在处理大数字或需要确保结果在特定范围内时(例如,对于自定义整数大小)。

步骤 7:返回结果: 处理完所有位后,最终结果将是所有位都已反转的数字。返回或显示结果。

输出

 
Inverted bits of 5 is: -6   

复杂度分析

时间复杂度

程序的时间复杂度为 O(1),因为循环运行固定次数的迭代(Java 中的整数为 32 位)。迭代次数不取决于输入的大小,因此这是一个恒定时间操作。

空间复杂度

此方法在 O(1) 空间复杂度下运行,因为它仅使用恒定的内存量。结果 变量 和其他几个变量(如循环计数器和位掩码)会被使用,但它们的内存使用量不会随着输入的大小而增长,因此这是一个恒定空间操作。

优点

  • 定制: 该方法提供了对过程的更多控制。如果需要,您可以调整或扩展逻辑以包含更复杂的按位操作。
  • 教育性: 这是深入学习和理解按位操作的好方法,因为您正在手动处理每一位。
  • 灵活性: 我们可以适应此方法来处理非标准场景(例如,处理不同位宽的数字或执行其他检查)。
  • 可移植性: 该方法是平台无关的。即使在按位非不支持原生支持的情况下,也可以实现手动操作。

下一个主题Java BF