当前位置: 首页 > news >正文

【LeetCode 每日一题】1733. 需要教语言的最少人数

Problem: 1733. 需要教语言的最少人数

文章目录

  • 整体思路
  • 完整代码
  • 时空复杂度
    • 时间复杂度:O(M*L + F*L + N*(T+M))
    • 空间复杂度:O(M*N + T)

整体思路

这段代码旨在解决一个关于语言教学的优化问题。问题背景是:有一群用户,每个人会说一种或多种语言。还有一些好友关系。如果一对好友不能直接交流(即他们没有任何共同语言),那么他们就构成了“无法交流”的好友对。我们需要选择一种语言,教给尽可能少的人,使得所有这些“无法交流”的好友对都能通过这门新教的语言进行交流。问题要求返回需要教学的最少人数。

该算法的思路清晰,分为三个主要步骤:预处理 -> 筛选 -> 暴力枚举

  1. 第一步:预处理

    • 为了能够快速查询某个人是否会说某种语言,算法首先创建了一个 m x (n+1) 的布尔二维数组 learned
    • learned[i][j]true 表示用户 i 会说语言 j
    • 通过遍历输入的 languages 数组,将这个 learned 查找表填充好。这避免了在后续步骤中反复线性搜索每个用户的语言列表。
  2. 第二步:筛选出无法交流的好友对

    • 算法的核心是只关注那些当前无法交流的好友对,因为只有他们才需要我们去解决问题。
    • 代码遍历 friendships 数组。对于每一对好友 (u, v)
      • 它会检查他们是否有共同语言。通过遍历用户 u 的所有语言 x,并在 learned 查找表中查询 v 是否也会说 x (learned[v][x])。
      • 如果找到了任何一种共同语言,说明这对好友可以交流,直接使用 continue next;(带标签的continue)跳到外层循环,处理下一对好友。
      • 如果遍历完 u 的所有语言都没有找到共同点,说明这对好友无法交流。将这对好友 [u, v] 加入到一个 todoList 中。
    • 循环结束后,todoList 中就包含了所有需要我们去“修复”关系的好友对。
  3. 第三步:枚举所有语言作为通用语

    • 现在,我们需要从 1nn 种语言中,选择一种作为“通用教学语言”。
    • 算法采用暴力枚举的方式,遍历每一种可能的语言 k(从1到n)。
    • 对于每一种被选作通用语的语言 k,它计算需要教多少人才能让 todoList 中的所有好友都能交流。
      • 创建一个 HashSet<Integer> set,用于存储需要被教语言 k不重复的用户ID。
      • 遍历 todoList 中的每一对无法交流的好友 (u, v)
      • 为了让 uv 能通过语言 k 交流,他们必须会说语言 k
      • 检查 u 是否会说语言 k (!learned[u][k]),如果不会,就把 u 加入 set
      • 检查 v 是否会说语言 k (!learned[v][k]),如果不会,就把 v 加入 set
    • 当遍历完 todoList 后,set.size() 就是选择语言 k 作为通用语时,需要教学的总人数。
    • ans = Math.min(ans, set.size()):用这个值去更新全局的最小教学人数 ans
  4. 返回结果

    • 在枚举完所有可能的通用语言后,ans 中存储的就是最终的最小值,将其返回。

完整代码

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;class Solution {/*** 计算最少需要教多少人,才能让所有好友都能交流。* @param n           语言的总数* @param languages   每个用户会的语言列表* @param friendships 好友关系列表* @return 最少需要教学的人数*/public int minimumTeachings(int n, int[][] languages, int[][] friendships) {int m = languages.length; // 用户总数// 步骤 1: 预处理,创建一个快速查询表// learned[i][j] = true 表示用户 i 会说语言 jboolean[][] learned = new boolean[m][n + 1];for (int i = 0; i < m; i++) {for (int x : languages[i]) {learned[i][x] = true;}}// 步骤 2: 筛选出所有无法交流的好友对List<int[]> todoList = new ArrayList<>();next: // 标签,用于跳出内层循环到外层循环的下一次迭代for (int[] f : friendships) {int u = f[0] - 1; // 用户索引从0开始int v = f[1] - 1;// 检查 u 和 v 是否有共同语言for (int x : languages[u]) {if (learned[v][x]) {// 有共同语言,这对好友可以交流,跳过continue next;}}// 遍历完 u 的所有语言都没有共同点,加入待办列表todoList.add(f);}// 如果所有好友都能交流,无需教学,返回0if (todoList.isEmpty()) {return 0;}int ans = m; // 答案的上限是所有人都学一种新语言// 步骤 3: 枚举每一种语言 k 作为通用教学语言for (int k = 1; k <= n; k++) {// 使用 Set 来存储需要被教语言 k 的不重复的用户Set<Integer> set = new HashSet<>();// 遍历所有无法交流的好友对for (int[] f : todoList) {int u = f[0] - 1;int v = f[1] - 1;// 如果 u 不会说语言 k,则需要教他if (!learned[u][k]) {set.add(u);}// 如果 v 不会说语言 k,则需要教他if (!learned[v][k]) {set.add(v);}}// 更新全局最小教学人数ans = Math.min(ans, set.size());}return ans;}
}

时空复杂度

时间复杂度:O(ML + FL + N*(T+M))

  1. 预处理 learned 数组 (步骤1)

    • 遍历 m 个用户,每个用户的语言列表平均长度为 L
    • 时间复杂度为 O(M * L),其中 Llanguages[i] 的最大长度。
  2. 筛选 todoList (步骤2)

    • 遍历 F 个好友关系。
    • 对于每对好友,内层循环遍历其中一个用户的语言列表,长度为 L
    • 时间复杂度为 O(F * L),其中 Ffriendships 的长度。
  3. 枚举语言 (步骤3)

    • 外层循环遍历 N 种语言。
    • 内层循环遍历 todoList,其大小设为 T ( T <= F )。
    • 在循环内部,set.add() 操作的平均时间复杂度是 O(1)。
    • 因此,这部分的时间复杂度为 O(N * T)

综合分析
总的时间复杂度是以上三部分之和:O(M*L + F*L + N*T)。这是一个比较复杂的表达式,取决于各个输入参数的大小。在题目给定的约束下,这个复杂度是可接受的。

空间复杂度:O(M*N + T)

  1. learned 数组

    • 创建了一个 m x (n+1) 的布尔数组。
    • 空间复杂度为 O(M * N)
  2. todoList 列表

    • 在最坏情况下,所有好友对都无法交流,列表大小为 F (好友关系数)。
    • 空间复杂度为 O(F)。设需要处理的好友对为T,则为 O(T)
  3. set 集合

    • 在枚举循环中,set 的大小在最坏情况下可能包含 todoList 中所有涉及的用户。
    • 最多有 2*T 个用户被加入,所以空间复杂度为 O(T)
    • 这个空间是可复用的,每次外层循环都会创建一个新的set

综合分析
算法所需的额外空间主要由 learned 数组和 todoList 决定。因此,总的空间复杂度为 O(M*N + T)

http://www.dtcms.com/a/392653.html

相关文章:

  • 多模态知识图谱
  • 基于python spark的航空数据分析系统的设计与实现
  • 【每日一问】运放单电源供电和双电源供电的区别是什么?
  • LeetCode算法领域的经典题目之“三数之和”和“滑动窗口最大值”问题
  • SpringCloudConfig:分布式配置中心
  • Go变量与类型简明指南
  • 每天学习一个统计检验方法--曼-惠特尼U检验(以噩梦障碍中的心跳诱发电位研究为例)
  • linux创建服务器
  • 线性代数基础 | 零空间 / 行空间 / 列空间 / 左零空间 / 线性无关 / 齐次 / 非齐次
  • 【StarRocks】-- 同步物化视图实战指南
  • 【C++项目】微服务即时通讯系统:服务端
  • 开源WordPress APP(LaraPressAPP)文档:1.开始使用
  • 单调破题:当指数函数遇上线性方程的奇妙对决
  • 【C++】vector 的使用和底层
  • 指标体系单一只关注速度会造成哪些风险
  • 智能体落地与大模型能力关系论
  • QPS、TPS、RT 之间关系
  • Day27_【深度学习(6)—神经网络NN(4)正则化】
  • NeurIPS 2025 spotlight 自动驾驶最新VLA+世界模型 FSDrive
  • Nodejs+html+mysql实现轻量web应用
  • AI模型测评平台工程化实战十二讲(第二讲:目标与指标:把“测评”这件事说清楚(需求到蓝图))
  • 20.二进制和序列化
  • 接口自动化测试实战
  • 为企业系统无缝集成AI检测能力:陌讯AIGC检测系统API接口调用全指南
  • RESTful API
  • Linux知识回顾总结----进程间通信(上)
  • Qwen3-Next深度解析:阿里开源“最强性价比“AI模型,如何用3%参数超越全参数模型?
  • AutoResetEvent:C# 线程同步工具
  • ThinkSound - 阿里通义开源的AI音频生成模型
  • Wan2.2-S2V-14B:音频驱动的电影级视频生成模型全方位详解