2026年字节跳动春招算法岗的题已经陆续流出来了3月20日这一场的第四题《小红的红色直线》讨论度挺高。这道题表面是个几何题实际上考的是哈希去重、边界处理和一点点数论基本功属于典型的“看着害怕、想明白后代码很短”的题。我这两天把网上流传的回忆版整理成了一个可以复现的版本完整跑通了Java、C、Python三份代码今天把题目理解、推导过程、踩坑点和三种语言实现一次性写清楚。准备冲算法岗笔试的朋友尤其是奔着字节去的建议认真看完。1. 这道题到底在问什么1.1 还原后的题目描述这是根据多份面经和讨论帖整理的回忆版题目名字和个别细节可能和原题有出入但核心考点是一样的。题目描述在二维平面上有 n 个红色点第 i 个点的坐标是 (x_i, y_i)坐标都是整数保证没有重复点。一条直线被称为“红色直线”当且仅当它至少经过两个给定的红色点。请问一共有多少条不同的红色直线。输入格式第一行一个整数 n表示点的个数。接下来 n 行每行两个整数 x_i 和 y_i表示第 i 个点的坐标。输出格式一个整数表示不同红色直线的条数。数据范围回忆版常见范围1 ≤ n ≤ 5000|x_i|, |y_i| ≤ 10^5为什么要特别强调数据范围因为这道题的思路完全取决于 n 的量级。n 如果在 5000 以内O(n^2) 的枚举是可行的n 如果到 10^5O(n^2) 直接爆炸题目性质就完全不同了。从春招笔试的难度来看n 取 3000 到 5000 这个区间最合理既能考察哈希和去重能力又不至于让大部分人连暴力都写不出来。1.2 样例分析先给两个简单样例跑通之后对题意的理解就稳了。样例一3 0 0 1 1 2 2三个点都在 y x 这条直线上。虽然 C(3,2) 3 个点对能确定三组“两点连线”但连出来是同一条直线所以答案应该是 1。样例二4 0 0 1 0 0 1 1 1这是平面上的四个正方形顶点。任意两个点确定的直线都不共线或者说没有出现“三个点落在同一条直线上”的情况所以 C(4,2) 6 条直线全部不同答案是 6。如果只看这两个样例很多人会觉得这题就是求“有多少对点的连线不重复”但真正的难点藏在“三个及以上点共线”这种情况里。如果一条直线上有 4 个点那么这 4 个点两两之间能组成 6 个点对这 6 个点对都确定同一条直线必须只算一次。1.3 这题真正想考什么字节的算法岗笔试很少出纯数学题这道题的包装是“几何”内核其实是三个点几何对象的哈希表示怎么用整数精确表示一条直线而不是用浮点数。集合去重如何保证同一条直线只被计数一次。边界处理负坐标、垂直直线、水平直线、全部点共线等特殊情况。如果你在面试复盘时能把这三点说出来面试官会觉得你真的吃透了题目而不是背了个模板。2. 从暴力到正解完整思路推导2.1 为什么不能用浮点斜率很多人第一反应是算斜率把每条直线表示成 (斜率, 截距)然后放到 set 里去重。比如一条直线经过点 p1 和 p2斜率为 (y2-y1)/(x2-x1)截距为 y1 - 斜率*x1。这个思路方向是对的但直接用 double 会死得很惨。第一个问题是精度。double 的有效数字大概是 15 到 16 位十进制。坐标差如果到 10^5那么两条斜率极其接近的直线在 double 里可能被误判成同一条。比如 (0,0) 和 (100000,1) 连成的直线与 (0,0) 和 (100001,1) 连成的直线斜率差大概在 10^-10 量级double 勉强能分出来但如果你再叠加上截距的计算误差结果就不敢保证了。第二个问题是垂直直线。x1 x2 时斜率是无穷大你不得不单独写一个 if 分支。这个分支本身不复杂但它破坏了代码的统一性而且一旦某个坐标差是 0除法会直接出问题。第三个问题是同一直线的不同表示。一条直线上有多个点时你从不同的点对去计算斜率和截距得到的浮点结果会有细微差别比如 (0,1) 和 (2,2) 算出的斜率可能是 0.5而 (2,2) 和 (4,3) 算出的斜率可能是 0.5000000001。把它们当成不同直线去重答案就错了。正确的做法是用整数精确表示几何方向完全抛弃浮点。2.2 最常见的错误方向数累加后除以 2我在网上看到不少人在讨论这道题时提出了一个看起来很聪明的方案枚举每个点作为基准点统计从它出发有多少个不同的方向把所有点的方向数加起来最后除以 2。这个方案初听很有道理。每条直线经过两个点直线 AB 在以 A 为基准时被数一次在以 B 为基准时被数一次所以总数除以 2 就是直线数。问题出在哪出在“一条直线上有 3 个及以上点”的情况。举一个最简单的例子平面上有 4 个点全部落在同一条直线上。以每个点为基准它到另外 3 个点的方向都是同一个所以每个点贡献 1 个方向4 个点合计贡献 4除以 2 得到 2。但正确答案是 1。这条直线实际上被数了 4 次而不是 2 次。更准确地说如果有 k 个点共线那么这条直线会被 k 个基准点各数一次总贡献是 k而不是 2。