剑指 Offer 64 题解:不借助循环与条件判断,用逻辑短路实现 1 + 2 + … + n
2026/9/16 17:32:28 网站建设 项目流程

剑指 Offer 64 题解:不借助循环与条件判断,用逻辑短路实现 1 + 2 + … + n

【免费下载链接】LeetCode-Book《剑指 Offer》《图解算法数据结构》《Krahets 笔面试精选 88 题》Python, Java, C++ 解题代码项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Book

本篇基于 LeetCode-Book 仓库 剑指 Offer 题解文档,详解「剑指 Offer 64. 求 1 + 2 + … + n」这道经典脑筋急转弯式算法题:如何在禁用乘除法、禁用 for/while 循环、禁用 if-else 与三目运算符的苛刻限制下,利用逻辑运算符的短路特性把递归作为循环的替身,完成累加计算。读完后你将掌握短路求值(short-circuit evaluation)在 Java、Python、C++ 三种语言中的行为差异,并能复现仓库中的可运行解法。

题目与限制条件

题目要求计算sum(1 + 2 + … + n),但对实现方式做了多重禁止:

  • 不能使用乘除法
  • 不能使用forwhile等循环语句
  • 不能使用if-else、三目运算符等条件判断语句

约束叠加后,常规思路全部失效,这道题本质上是在考察对语言级求值机制(尤其是逻辑短路)的理解深度。本文档给出的核心方法是:用排除法一步步排除常规方案,最终导向「短路效应 + 递归」的组合拳

排除法:三种常规方案为何全部被禁

方法一:平均计算(被乘除法禁令排除)

最直觉的公式是高斯求和:(1 + n) * n / 2,一步到位,但必须使用乘除法,直接违反题目限制,不可取。

public int sumNums(int n) { return (1 + n) * n / 2; }
def sumNums(n): return (1 + n) * n // 2
int sumNums(int n) { return (1 + n) * n / 2; }

方法二:迭代累加(被循环禁令排除)

退而求其次可以逐项累加,但循环必须依赖whilefor,同样被排除:

public int sumNums(int n) { int res = 0; for (int i = 1; i <= n; i++) res += i; return res; }
def sumNums(n): res = 0 for i in range(1, n + 1): res += i return res
int sumNums(int n) { int res = 0; for (int i = 1; i <= n; i++) res += i; return res; }

方法三:递归(被条件判断禁令排除)

再进一步,可以用递归模拟累加,但标准的递归终止条件必须写if,依然不可取:

public int sumNums(int n) { if (n == 1) return 1; n += sumNums(n - 1); return n; }
def sumNums(n): if n == 1: return 1 n += sumNums(n - 1) return n
int sumNums(int n) { if (n == 1) return 1; n += sumNums(n - 1); return n; }

关键问题由此浮出水面:除了ifswitch这类判断语句,还有没有其他机制可以终止递归?答案正是短路效应。

核心原理:逻辑运算符的短路效应

常见的逻辑运算符有三种:「与&&」「或||」「非!」。它们有一个重要的短路(short-circuit)特性

if (A && B) // 若 A 为 false,则 B 的判断不会执行(即短路),直接判定 A && B 为 false if (A || B) // 若 A 为 true,则 B 的判断不会执行(即短路),直接判定 A || B 为 true

对于&&运算符:左侧表达式一旦为false,右侧表达式根本不会被求值。把这个特性反过来用——让左侧表达式充当递归的终止判断

n > 1 && sumNums(n - 1) // 当 n = 1 时 n > 1 不成立,此时发生“短路”,终止后续递归
  • n > 1true时,继续求值右侧的sumNums(n - 1),递归推进;
  • n = 1时,左侧为false,发生短路,sumNums(0)永远不会被调用,递归自然终止。

这样就把if (n == 1) return;这一句判断,等价地改写成了逻辑表达式,完美绕开了条件语句禁令。

最终解法:三语言实现

把短路表达式嵌入累加逻辑,即可得到最终答案。原文档给出的实现要点有 3 条,需要注意:

  1. Java 中,为构成完整语句,需要引入一个辅助布尔变量x接收表达式结果,否则编译报错;
  2. Java 中,开启递归的部分需改写为sumNums(n - 1) > 0,让整个右半部分作为一个布尔量参与&&运算,否则会报错;
  3. 用成员变量res记录累加结果(Java 也有不借助res的简洁写法)。

解法一:借助成员变量 res 累加

class Solution { int res = 0; public int sumNums(int n) { boolean x = n > 1 && sumNums(n - 1) > 0; res += n; return res; } }

执行顺序:先短路判断并触发递归(递归在res += n之前完成更深层的累加),再把当前n加入res

仓库中的 Java 解法一源码 与上述完全一致,并附带n = 3的测试驱动(期望输出6),可直接用 JDK 编译运行验证。

对应的 Python 版本利用了and表达式同样具备短路求值特性(且 Python 中表达式可直接作为语句,无需辅助变量):

class Solution: def __init__(self): self.res = 0 def sumNums(self, n: int) -> int: n > 1 and self.sumNums(n - 1) self.res += n return self.res

仓库中的 Python 解法源码 同样内置了n = 3的测试用例与驱动代码,可直接python3 sfo_64_solve_1_2___n_s1.py运行。

C++ 版本中&&是原生短路运算符,表达式求值结果可以直接丢弃(编译器会给出未使用值的提示但不影响运行),写法最为干净:

class Solution { public: int sumNums(int n) { n > 1 && (n += sumNums(n - 1)); return n; } };

对应源码见 C++ 解法,头文件依赖 include/include.hpp。

解法二:Java 无辅助变量写法

Java 还有第二栏的简洁写法,把累加动作直接嵌入短路表达式内部,完全不借助res

class Solution { public int sumNums(int n) { boolean x = n > 1 && (n += sumNums(n - 1)) > 0; return n; } }

原理:右侧(n += sumNums(n - 1))把递归返回值写回参数n本身(Java 形参按值传递,修改只影响本帧的n),随后> 0将其转换为布尔量参与&&运算,x只是满足语句语法的载体。仓库中的 Java 解法二源码 采用同样实现并带有n = 3的验证入口。

注意:解法二的技巧依赖于「把返回值累加回形参」这一副作用。如果递归深度过大,n可能溢出;且该写法把语义压缩进单行表达式,可读性较差,工程实践中更推荐解法一。

递归执行过程走查

sumNums(3)为例,按解法一(res成员变量版本)推演执行过程:

  1. sumNums(3)3 > 1成立,先递归调用sumNums(2)
  2. sumNums(2)2 > 1成立,先递归调用sumNums(1)
  3. sumNums(1)1 > 1false短路,不再递归(避免了sumNums(0)乃至负数的无意义调用);执行res += 1,返回res = 1
  4. 回到sumNums(2):执行res += 2res = 3
  5. 回到sumNums(3):执行res += 3res = 6,最终返回6

递归的「展开阶段」由短路表达式驱动,而累加动作发生在「回溯阶段」——每一帧返回前把自己的n记入res,最终得到1 + 2 + 3 = 6,与仓库中各语言测试驱动的输出一致。

复杂度分析

  • 时间复杂度 O(n):计算n + (n-1) + … + 2 + 1需要开启n层递归调用;
  • 空间复杂度 O(n):递归深度达到n,调用栈占用 O(n) 的额外空间。

从源码结构看,三语言解法的测试用例均取n = 3这类小输入;由于递归深度等于n,当n很大时(例如接近 Java 默认栈能容纳的调用层数),存在栈溢出(StackOverflowError)的风险,这是该解法以空间换语法的固有代价。

小结

方案核心手段被排除/可用的原因
平均计算(1+n)*n/2数学公式使用乘除法,违反限制
迭代累加for/while循环语句使用循环,违反限制
标准递归 +if终止条件判断使用if,违反限制
短路 + 递归(最终解法)&&短路求值仅用逻辑表达式,通过所有限制

本题的价值不在于「求和」本身,而在于演示了一条通用的规避技巧:当语言禁止某种语法结构时,可以寻找具有等价控制流副作用的语言级机制来替代——条件判断可以被逻辑短路替代,循环可以被递归替代。仓库中sfo_64_solve_1_2___n_s1sfo_64_solve_1_2___n_s2两套 Java 实现分别展示了「辅助变量累加」与「形参回写」两种落地风格,配合 Python 与 C++ 版本,为三种语言下短路语义的细微差异(是否需要辅助语句、表达式能否作为独立语句、结果值是否可丢弃)提供了可直接编译运行的对照素材。

【免费下载链接】LeetCode-Book《剑指 Offer》《图解算法数据结构》《Krahets 笔面试精选 88 题》Python, Java, C++ 解题代码项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Book

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询