找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2066

积分

0

好友

294

主题
发表于 2025-12-30 05:12:58 | 查看: 22| 回复: 0

刚看到一个帖子,讲的是一次略显意外的面试经历。一位网友面试了一位45岁的程序员,对方期望月薪是两万,面试官觉得人合适,当场就同意了。结果送对方到电梯口时,这位候选人补了一句:“如果公司能提供14薪的话,月薪一万八也行。”

脉脉社交媒体帖子截图:讨论45岁程序员面试谈薪
图1:脉脉社区关于45岁程序员面试谈薪的讨论截图

帖子内容很简单,核心就是一次临门一脚时的薪资谈判。评论区观点分成两派,有人说这位程序员太会算计,步步试探底线;也有人表示理解,认为中年程序员考虑更现实,想把年度总包谈清楚。

我的看法是,这件事的关键可能不在于具体金额,而在于沟通的时机。谈薪资有时就像市场交易,价格都谈妥准备成交了,突然再来一句“能不能再便宜点”,容易让对方心里产生犹豫。特别是对于45岁这个阶段的候选人,企业招聘时往往更看重稳定和明确的预期,而不是反复的变化。

当然,站在中年人的角度,谨慎一些完全可以理解,毕竟肩上的担子不轻。只是在职场沟通中,清晰和直接有时比“聪明”的试探更重要。这场关于面试谈薪技巧的讨论,也反映出职场沟通的复杂性。

算法题:有趣的电影 – 二级关注者问题

聊完面试,我们切换到一个有趣的算法场景。假设你是一个博主,平台可以是小红书或者B站。

  • 直接关注你的人,是你的 一级关注者
  • 这些粉丝自己也会去关注别人,对吧?
  • 那些“关注了你的粉丝”的人,但 没直接关注你、也不是你自己,这一部分人,就可以称为 二级关注者

转换到算法世界,这就是一个典型的有向图问题。一条边 u -> v 表示:u 关注 v

题目会给你一堆这样的关注关系,再给你一个目标用户 x,要求你计算:所有满足——“关注了某个一级关注者,但自己不是 x,也没直接关注 x”——的用户集合。

输出可以是这个集合的人数,也可以是集合本身,具体看题目要求。

思路拆解:先别急着想DFS、BFS

首先要把方向搞清楚:边是 u -> v(u 关注 v),那么对于用户 v 来说,“谁关注了我”其实是看指向 v入边

所以,对目标用户 x 的二级关注者计算可以分三步:

  1. 找一级关注者:找到所有 u,满足有边 u -> x。这就是一级关注者集合 F1
  2. 找候选者:对每一个一级关注者 f ∈ F1,找到所有 w,满足 w -> f。这些 w 就是“关注了你粉丝的人”,也就是二级关注者的候选。
  3. 过滤:把这些候选 w 放入一个集合去重,然后排除掉:
    • 用户 x 自己。
    • 已经在 F1 中的人(即一级关注者)。
    • 不能直接关注 x(上一个条件其实已经保证了这一点)。

本质上,这就是一个 两层“谁关注了谁”的反向查询,严格来说不需要复杂的图算法,核心是理解图的邻居关系。

数据结构怎么选?

这里有两个关键点需要考虑:

  1. 数据存储是按“谁关注谁”(出边)存,还是“谁被谁关注”(入边)存?
  2. 查询时,如何尽量减少扫描无关数据?

因为我们的查询需求都是“谁关注了当前这个人”,所以使用 反向邻接表 会非常方便:
followers[v] = 所有满足 u -> v 的 u 的集合

这样做的好处是:

  • 建图:一次性扫描所有边 (u, v),将 u 加入 followers[v],时间复杂度 O(m)。
  • 查一级关注者:直接就是 followers[x]
  • 查二级候选:对每个一级关注者 f in followers[x],把 followers[f] 合并起来即可。

整体时间复杂度大致是 O(m + |F1| + 所有F1的粉丝总数),在常规场景下完全够用。

下面,我们用一个清晰的函数来实现它。这类图论与数据结构的结合问题在面试中很常见。

  • 输入
    • n: 用户总数(ID 范围 0 ~ n-1)
    • edges: 关注关系列表,每个元素是 [u, v] 表示 u 关注 v
    • target: 目标用户 id
  • 输出
    • 目标用户的二级关注者集合(如果只要计数,取 len(result) 即可)

直接上 Python 代码:

from collections import defaultdict
from typing import List, Set

def second_level_followers(n: int, edges: List[List[int]], target: int) -> Set[int]:
    """
    计算目标用户的二级关注者集合。

    :param n: 用户总数,用户 id 默认是 0 ~ n-1
    :param edges: 关注关系列表 [u, v],表示 u 关注 v
    :param target: 目标用户 id
    :return: 二级关注者的集合
    """
    # 构建“被谁关注”的反向邻接表
    followers = defaultdict(set)  # followers[v] = 关注 v 的所有用户
    for u, v in edges:
        if 0 <= u < n and 0 <= v < n:
            followers[v].add(u)

    # 1. 一级关注者:直接关注 target 的人
    level1 = followers.get(target, set())

    # 2. 所有候选二级关注者:关注了一级关注者的人
    candidates = set()
    for f in level1:
        candidates |= followers.get(f, set())

    # 3. 过滤掉不合法的:
    #    - 不能是自己
    #    - 不能是一级关注者
    #    - 也不能是没必要的重复(集合天然去重了)
    result = set()
    for u in candidates:
        if u == target:
            continue
        if u in level1:
            continue
        # 如果题目要求“不能直接关注 target”,这里再保险判断一下:
        if target in followers and u in followers[target]:
            continue
        result.add(u)

    return result

if __name__ == "__main__":
    # 构造示例:
    # 0 关注 1
    # 2 关注 1
    # 3 关注 0
    # 4 关注 0
    # 5 关注 2
    #
    # 对于 target = 1:
    #   一级关注者:{0, 2}
    #   二级关注者候选:
    #       关注 0 的有 {3, 4}
    #       关注 2 的有 {5}
    #   过滤后结果:{3, 4, 5}
    n = 6
    edges = [
        [0, 1],
        [2, 1],
        [3, 0],
        [4, 0],
        [5, 2],
    ]
    target = 1

    res = second_level_followers(n, edges, target)
    print("二级关注者集合:", res)
    print("人数:", len(res))

运行上面的代码,你会得到输出:

二级关注者集合: {3, 4, 5}
人数: 3

你看,一道披着“社交”外衣的题目,核心锻炼的是 图建模能力、合理选择数据结构以及基础的集合运算,用 Python 实现起来也非常简洁。技术讨论的魅力就在于此,从一个现实话题可以延伸到严谨的算法世界。这类结合生活场景的算法题,在技术社区如云栈社区中往往能引发更深入的探讨。




上一篇:OpenAI以400万年金急聘灾备负责人,直面AI心理健康与安全挑战
下一篇:支付宝“碰一下”4个月用户破2亿,移动支付战局生变
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-11 20:16 , Processed in 0.431903 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表