Swift 解法详解:LeetCode 371《两整数之和》


文章目录

摘要

这道题看起来很奇怪:我们要计算两个整数的和,但题目规定 不能用 + 或 - 运算符 。听起来像是脑筋急转弯,其实这是一个很经典的"位运算"应用题。通过理解二进制的加法规则,我们完全可以用 位运算 来模拟加法过程。

这类题不仅能训练我们的思维,还能加深对二进制和位操作的理解。在底层开发、嵌入式开发甚至编译器优化里,这些技巧都非常实用。

描述

题目要求:

给你两个整数 a 和 b,不能用 + 或 - 运算符,返回它们的和。

示例 1

txt 复制代码
输入: a = 1, b = 2
输出: 3

示例 2

txt 复制代码
输入: a = 2, b = 3
输出: 5

提示

  • -1000 <= a, b <= 1000

题解答案

要模拟加法,首先回忆一下二进制的运算规则:

  • 不带进位的加法(相当于 XOR 异或):

    • 0 ^ 0 = 0
    • 1 ^ 0 = 1
    • 0 ^ 1 = 1
    • 1 ^ 1 = 0
  • 进位的部分(相当于 AND 与运算,再左移一位):

    • 只有当两位都是 1 时才产生进位。

因此:

  • 用 a ^ b 计算不带进位的和。
  • 用 (a & b) << 1 计算进位。
  • 然后不断迭代,把"和"和"进位"相加,直到进位为 0。

这就是用位运算模拟加法的核心思想。

题解代码分析

下面是 Swift 实现:

swift 复制代码
import Foundation

class Solution {
    func getSum(_ a: Int, _ b: Int) -> Int {
        var x = a
        var y = b
        
        while y != 0 {
            // 非进位和
            let sum = x ^ y
            // 进位
            let carry = (x & y) << 1
            // 更新 x 和 y
            x = sum
            y = carry
        }
        
        return x
    }
}

// MARK: - Demo 演示
let solution = Solution()
print(solution.getSum(1, 2)) // 输出: 3
print(solution.getSum(2, 3)) // 输出: 5
print(solution.getSum(-2, 3)) // 输出: 1

代码拆解

  1. 初始化变量

    • x 表示当前的和(不带进位)。
    • y 表示进位。
  2. 循环模拟加法

    • sum = x ^ y:这是当前两数的无进位和。
    • carry = (x & y) << 1:这是进位。
    • 更新 x = sum,y = carry,继续迭代。
  3. 终止条件

    • 当进位 y = 0 时,说明没有更多进位了,x 就是最终的答案。

示例测试及结果

运行 Demo 代码:

txt 复制代码
输入: (1, 2)
输出: 3

输入: (2, 3)
输出: 5

输入: (-2, 3)
输出: 1

结果完全符合预期。

这个方法不仅适用于正数,也适用于负数,因为 Swift 的 Int 本质上是补码存储,位运算同样适用。

时间复杂度

  • 每次循环至少会让进位左移一位,所以最多执行 O(32) 次(对于 32 位整数)。
  • 在 Swift 中 Int 是 64 位的,也就是最多执行 O(64) 次。
  • 复杂度可以认为是 O(1)。

空间复杂度

  • 只用了常量级的几个变量,空间复杂度是 O(1)。

总结

这道题的关键在于理解:

  • a ^ b 负责"加法不带进位"的部分。
  • (a & b) << 1 负责"进位"的部分。
  • 不断迭代直到进位为 0。

这个方法绕开了 + 和 -,用纯粹的位运算模拟了加法的过程。

在实际场景中,位运算往往出现在底层优化或者特殊硬件环境中。比如:

  • 处理器底层 ALU 的加法实现。
  • 高性能计算场景里的快速运算。
  • 特定场景下避免溢出的操作。

掌握这类思路,可以帮助我们更好地理解计算机是如何在底层执行算术运算的。

相关推荐
Elastic 中国社区官方博客3 小时前
我们如何通过 70 多个拉取请求,将 OpenTelemetry Java agent 迁移到 invokedynamic
java·大数据·开发语言·elasticsearch·搜索引擎·全文检索·es
tyn1883 小时前
记录本地安装nacos服务的方法及异常
java·开发语言
步行cgn4 小时前
Spring MVC 视图机制的核心接口与类
java·开发语言·后端·spring·mvc
y1su4 小时前
Leetcode 字符串模板
java·数据结构·算法·leetcode·职场和发展·动态规划
传奇开心果编程4 小时前
【Rust入门练中学】第5课:引用与借用
开发语言·rust·引用·编程语言理论·通用编程语言·借用
qetfw4 小时前
Bash 变量:export、位置参数与默认值展开验证
linux·开发语言·chrome·bash
电子云与长程纠缠5 小时前
UE5魂系游戏开发教程05
开发语言·学习·游戏·ui·ue5
cspttty5 小时前
2027风险管理岗准备路线:数学与应用数学如何补齐金融、SQL与Python
开发语言·python·金融
我命由我123455 小时前
Python 开发 - Python 的 pathlib
java·开发语言·后端·python·学习·java-ee·学习方法
严谨的麻辣烫6 小时前
Python HTTP 连接池怎么用?从连接复用到请求异常排查
开发语言·python·http·requests·网络排查