
交错序列求和这个题我几乎每次给新人讲循环和分支的时候都会拿出来当例子。题目本身不长就一句话给定一个正整数 n计算 1 - 2 3 - 4 ... 一直到第 n 项符号一正一负交替出现。看起来简单得不能再简单但你真让人当场写出来十个里面少说有三四个会在符号上翻车要么第一个数算成负数要么奇数个项的时候结果不对。这篇文章我不打算只给一个答案而是把从读题、思路、三种解法到代码细节、常见坑位全部拆开讲一遍适合刚开始学编程的人也适合准备笔试面试想快速复习基础题的人。1. 先把这个题目吃透交错序列是什么1.1 题目到底在求什么所谓交错序列就是一正一负交替出现的数列。以最常见的整数版本为例序列是 1, -2, 3, -4, 5, -6, ...第 i 项的通项可以写成 (-1)^(i1) * i。题目要求的其实就是这个序列的前 n 项之和。有些题会换一种问法比如“求符号交替的平方和”或者“求符号交替的奇数项和”但核心套路完全一样先看懂符号变化规律再决定怎么累加只是数值会被替换成别的表达式。我先列几个具体的数方便待会儿对答案。n1 时结果是 1n2 时 1 (-2) -1n3 时再加 3结果是 2n4 时再减 4结果是 -2。继续写到 n5结果变成 3n6结果变成 -3。这个规律非常明显奇数项结束就是正的结果约等于 (n1)/2偶数项结束就是负的结果是 -n/2。很多人忽略这一步直接写代码写到一半才发现符号怎么都不对就是因为没在纸上先找一个 pattern。我自己的习惯是拿到任何一道和数列有关的题先手算前 5 项把这个数列喂给自己的直觉。这里你很快会发现它不像等差数列那样单调增长而是“正一下、负一下”地来回跳但相邻两项可以看成一个整体。这个观察会直接影响后面解法选型所以千万别跳过。1.2 基础题背后真正考察的东西基础第 2 题这个定位其实很有意思。它一般不要求你懂什么高深算法而是考三个基本功。第一看你能不能把自然语言描述翻译成循环结构。这里没有复杂条件就是按顺序从 1 到 n 遍历每项按自己的符号加进去。第二看你会不会处理“状态切换”。这里的状态就是当前这一项该正还是该负对应到代码里就是一个符号变量。状态切换是编程里非常常见的模型比如贪吃蛇移动方向、UI 里的选中态切换都可以理解成这种开关。第三看你的边界意识n1、n0 甚至输入一个超大数代码是不是都能给出合理结果。我见过一些写了几年代码的人遇到这种基础题反而写法很糟糕。比如有人用 pow(-1, i) 每次去算符号能用但效率低不说还掩盖了“符号是状态”这个本质循环里每轮做一次幂运算完全是浪费。所以这道题的价值不是让你背一个正确答案而是帮你建立一个更好的代码直觉能用状态切换解决的就不要每次重新计算。2. 解题思路三连循环、配对和公式2.1 最稳妥的循环写法符号开关先讲最朴素、也是绝大多数人第一反应的写法维护一个 sum 累加再维护一个 sign 表示当前项的符号每处理完一项就让 sign 取反。伪代码大概是这样sum 0 sign 1 for i 1 to n: sum sum sign * i sign -sign这里的关键点是 sign 初始化为 1代表第一项是正。循环体里先累加、后取反顺序不能反你要是写成先取反再加第一项就会变成 -1。我见过不少新人在这两个语句的先后顺序上纠结其实只要想清楚“用当前符号处理当前项然后才准备下一项”顺序就很自然了。这个写法的优点是逻辑直白、不容易错而且很好调试。缺点是时间复杂度 O(n)。如果 n 只有几千几万完全没问题但 n 到一亿在单线程程序里就能明显感到卡顿。刷题平台如果设置了超时这种写法就可能过不了所以它适合用来理解原理不适合无脑套用到所有场景。2.2 成对分组不用硬算的小技巧其实稍微观察一下就能发现相邻两项可以凑成一组1 - 2 -13 - 4 -15 - 6 -1每一组的贡献都是固定的 -1。于是问题简化成看 n 里能凑出多少组以及最后有没有落单的一项。如果 n 是偶数一共 n/2 组总和就是 -n/2。如果 n 是奇数前 n-1 项凑成 (n-1)/2 组每组 -1最后一项是正的 n所以总和是 n - (n-1)/2。化简一下就是 (n1)/2。这个过程和 2.1 的循环写法在本质上做的是同一件事但思考方式完全不同一个是一步一步算一个是先把结构拆开。这种配对思维在算法里非常常用。以后你会见到很多“看似每次都不一样但相邻项一合并就变成定值”的题比如部分差分题、数列周期性问题都可以试着找固定组合。它不是背出来的技巧而是一种观察角度看到正负交替、奇偶交错这种词第一时间就可以往“两两分组”上想。2.3 一步到位的通项公式再往下推一步把上面的结果合并成一个公式。设 n 2k 时sum -k设 n 2k1 时sum 2k1 - k k1。用代码判断就是if n % 2 0: sum -(n // 2) else: sum (n 1) // 2这个公式是 O(1) 的不管 n 多大只要在语言能表达的整数范围内都能瞬间算出来。实际做笔试题的时候这种公式法往往是加分项。但我也要说一句如果你是在学习阶段别急着直接背公式先把循环写明白再理解配对最后推导到公式整个过程才是完整的。公式法的坑也不是没有。很多人记住了“偶数时是负的 n/2”但写代码时把整数除法和浮点除法混用。C 语言里 n/2 对正数没问题对负数会向零取整和你预期的不一样。Python 里 // 是向下取整-1//2 的结果是 -1这些细节都会影响边界输入下的正确性所以严谨的代码最好先判断奇偶再计算。3. 代码实现与运行细节手把手跑通3.1 C语言版本注意返回值类型直接给一个可以跑的例子#include stdio.h long long alternating_sum(int n) { if (n 0) { return 0; } if (n % 2 0) { return -((long long)n / 2); } return ((long long)n 1) / 2; } int main(void) { int n; while (scanf(%d, n) 1) { printf(%lld\n, alternating_sum(n)); } return 0; }这里有两个细节值得讲。第一返回值用 long long 而不是 int。交错序列的和看起来不大但 n 取到 2,000,000,000 附近时奇数分支的结果约 1,000,000,001还没超过 32 位 int 上限可一旦题目把 n 放大到更大范围或者你把 n 做了乘法运算int 说溢出就溢出。养成用更宽类型的习惯能少踩很多雷。第二表达式 -((long long)n / 2) 要注意优先级。这里我先用 (long long)n 把 n 转成 64 位整数再做整除最后取负逻辑非常直白。如果你写成 -(long long)n / 2在 C 语言里单目减号优先级高于除法实际是 (-(long long)n) / 2结果虽然一样但可读性差一些代码 review 时容易引起误会。测试的时候线上线下一起看n1 输出 1n2 输出 -1n3 输出 2n4 输出 -2n5 输出 3。这几个用例通过基本说明公式分支没写反。我还会再加一个 n100结果应该是 -50这个用例很容易心算适合快速验证。3.2 Python版本三种写法对照Python 写起来更灵活我通常给学习者看三版。第一版是最接近人类直觉的循环def alternating_sum_loop(n: int) - int: total 0 sign 1 for i in range(1, n 1): total sign * i sign -sign return total第二版用生成器表达式代码很短但初学者容易在符号上绕晕def alternating_sum_comprehension(n: int) - int: return sum((-1) ** (i 1) * i for i in range(1, n 1))这里的 (-1) ** (i 1) 在 i 从 1 开始时i1 为偶数时结果为正也就是第一项为正数。如果 i 从 0 开始遍历符号刚好反过来很多人就在这里写错。所以如果你是初学者我更推荐显式的 sign 变量写法一眼能看出当前符号是什么。第三版是 O(1) 公式和 C 版本逻辑一致def alternating_sum_formula(n: int) - int: if n 0: return 0 if n % 2 0: return -(n // 2) return (n 1) // 2Python 的整数没有固定位宽所以不用担心溢出。但公式法仍然推荐因为 n 大了之后循环和生成器都会明显慢下来。面试官还可能直接问你能不能不用循环这时候把配对和推导过程讲一遍比贴代码更能体现水平。3.3 性能对比与写法选择我给一个粗糙的数量级概念。如果 n 是 10^6循环版在普通机器上大概几毫秒到几十毫秒看起来也不是很慢。但 n 到 10^8 甚至 10^9循环版就会从“毫秒”变成“秒”如果题目限制 1 秒很可能超时。公式版不管 n 多大都是常数时间在内存上也几乎不占额外空间。所以选择建议是这样的学习和教学阶段优先写循环它是理解状态切换的必经之路笔试题里先看 n 的范围如果 n 很大或者有多组测试数据直接用公式如果题目明确要求“模拟这个过程”比如让你打印每一步的累加结果那就老老实实循环。不要觉得公式法一定最高级合适才是最好的。有人可能会问既然公式这么简单平时写业务代码能不能也这样算我的看法是如果你的业务里确实有大量这种正负交替的统计当然可以但一定加注释把公式推导过程写清楚否则三个月后你自己回来看代码很可能想不通为什么偶数分支要取负。4. 踩坑记录常见错误和快速排查4.1 符号错乱最常见也最隐蔽第一个高发坑是符号方向反了。典型表现n2 时应该输出 -1结果却输出 1。排查方法很简单在纸上展开循环把每一轮的 i、sign、total 都写出来。绝大多数情况下你会发现要么 sign 初始值设成 -1要么先取反后累加顺序搞反了。第二个相关坑是用条件表达式区分符号时把条件写错。比如有人写 total i * (i % 2 ? 1 : -1)这个本身没问题但 i 从 0 开始遍历时判断条件就要改成 ((i 1) % 2 ? ... )。这些细节是纯粹的注意力测试没有捷径只能靠多写多错多记。第三个我特别想说别在循环里调用 pow(-1, i) 来切换符号。虽然它也能算出 1 和 -1但 pow 的开销远大于一次取反而且部分语言的 pow 对整数会走浮点路径i 很大时可能有精度隐患。这是典型的“能用但不好”的写法代码能跑但性能和行为都不够漂亮。4.2 边界值翻车n0 和 n1很多人把代码写得很顺一到边界就露出马脚。n1 时公式法走奇数分支返回 (11)/2 1没问题。循环法进入一次循环也没问题。真正麻烦的是 n0 或 n0。题目一般说正整数但你写防御性代码时总得想一想如果输入是 0返回 0 肯定比返回一个奇怪值要合理否则调用方可能拿一个垃圾值继续运算。还有一种边界是数据范围上限。如果题目给出 n 最大到 2^31 - 1用 int 接收没问题但计算 (n1)/2 时n1 在 32 位 int 里可能溢出变成负数。这就是为什么我上面建议先把 n 转成 long long。整数溢出是 C/C 里最容易无声出现的 bug它不会立刻报错而是在某个随机数据点上突然给你一个完全不合理的结果。另外要注意不同语言对负数除法行为不一样。C 的 / 在 C99 之后是向零取整Python 的 // 是向下取整如果题目考虑负数输入你最好统一用“先判断奇偶再各自处理”的方式不要依赖除法向哪个方向取整。4.3 排查问题速查表整理一个速查表碰到问题先对号入座现象可能原因解决办法所有结果都是正数sign 没有在循环里取反在累加后执行 sign -sign第一个数是负数sign 初始值写成 -1把 sign 初始值改为 1偶数 n 结果对奇数 n 结果差一点分组逻辑的落单项处理错奇数时最后一项是正数 n不是加 n-1n 很大时输出变成异常数字int 溢出返回值用 long long或使用 Python公式法 n0 输出非 0缺少 n 0 分支增加早退判断循环超时O(n) 在大数据量下太慢换配对法或公式法这张表是我自己刷题和帮人 review 代码时总结出来的照着查往往比从头看代码更快。我特别想说最后一行很多人觉得超时是优化问题实际上很多超时都是算法复杂度选错了把循环换成公式问题直接消失。5. 从这道题延伸出去5.1 面试官喜欢怎么追问基础题最容易被面试官加戏。我总结过几个高频追问每一个都在考同一套底层能力。第一个追问写递归版本。递归版代码很短def alternating_sum_recursive(n: int) - int: if n 0: return 0 if n % 2 1: return alternating_sum_recursive(n - 1) n return alternating_sum_recursive(n - 1) - n但这个写法的调用深度是 nn 到几千就可能栈溢出。能写出递归说明你理解递推关系能主动指出栈溢出风险说明你知道边界和性能问题这两点都是加分项。第二个追问改成交错分数序列求 1 - 1/2 1/3 - 1/4 ... 的前 n 项和。这就开始涉及浮点精度、四舍五入和收敛性质了。这个级数在 n 趋近无穷大时会收敛于 ln2但计算机求浮点和数学分析不是一回事n 很大之后后面项小到可能被前面的和“吃掉”这也是数值分析里常见的“小项被大项掩盖”问题。第三个追问有 m 次询问每次给一个不同的 n求对应的和。这时候每次用公式是 O(1)整体 O(m)已经很好。面试官此时往往不是真的要你再优化而是看你会不会提“多组询问可以预处理结果”或者反过来发现公式法已经是最优直接讲清楚复杂度就够了。5.2 数学背景和实际应用的联想讲点轻松的。整数交错序列本身是发散的部分和交替增减、离原点越来越远。但这种“正负交替”的思维在真实场景里很常见现金流有收入有支出信号处理里的差分信号有正有负机器学习里梯度更新的符号也可能上下跳动。很多时候把一对正负项放在一起观察比一个个累加更能看出趋势这就是配对思维的实际价值。我记得有一次帮朋友调一个累计收益计算的脚本他的数据里有买入价、卖出价、手续费和分红字段很多但核心就是一堆带正负号的数字求和。我第一反应就是这个基础题先分组再判断边界不要无脑在循环里逐项乘符号。最后脚本从跑几十秒优化到秒出。一个基础题的思路直接映射到业务场景这种例子越多越说明基础题值得认真吃透。最后分享一点个人体会。带人刷题这些年我发现基础题虐人从来不是因为题目难而是因为大家急着写代码不肯在纸上先推几个用例。交错序列求和这个题你只要先手算出 n1 到 5 的结果奇偶规律就摆在眼前解法自然就出来了。写完公式之后也别得意用 n1、2、3、4 各跑一遍确认奇偶分支没写反再提交。这个习惯能帮你省下大量 debug 时间。