在大厂面试中,与拓扑排序相关的问题通常涉及到对图的处理和算法设计。以下是三道可能出现在大厂面试中的编程题目,以及相应的Java源码实现。
题目 1:课程依赖关系
描述 :
给定一个课程列表和课程之间的依赖关系,为所有课程安排一个上课时间表。每个课程都有一个先修课程列表,如果课程 A 依赖于课程 B,则 B 必须在 A 之前上课。返回一个按时间顺序排列的课程列表,如果无法安排,则返回空列表。
示例:
输入: [["a", "b"], ["b", "c"], ["a", "c"]]
输出: ["a", "b", "c"]
Java 源码:
java
import java.util.*;
public class CourseSchedule {
private Map<String, List<String>> graph;
private Set<String> visited;
private List<String> order;
public List<String> findOrder(String[] courses) {
graph = new HashMap<>();
visited = new HashSet<>();
order = new ArrayList<>();
for (String course : courses) {
String[] coursePair = course.split(", ");
if (!graph.containsKey(coursePair[1])) {
graph.put(coursePair[1], new ArrayList<>());
}
graph.get(coursePair[1]).add(coursePair[0]);
}
for (String course : graph.keySet()) {
if (!visited.contains(course)) {
dfs(course);
}
}
return order.isEmpty() ? new ArrayList<>() : order;
}
private void dfs(String course) {
visited.add(course);
for (String preCourse : graph.get(course)) {
if (!visited.contains(preCourse)) {
dfs(preCourse);
}
}
order.add(0, course); // 逆序添加到列表中以保持拓扑顺序
}
public static void main(String[] args) {
CourseSchedule solution = new CourseSchedule();
String[] courses = {"a, b", "b, c", "a, c"};
List<String> result = solution.findOrder(courses);
System.out.println("Course order: " + result);
}
}
题目 2:项目任务调度
描述 :
给定一个项目任务列表和任务之间的依赖关系,每个任务都有一个唯一的标识符和一个任务完成时间。如果任务 A 依赖于任务 B,则 B 必须在 A 之前完成。返回一个按完成时间顺序排列的任务列表,如果无法调度,则返回空列表。
示例:
输入: tasks = ["a(2)", "b(1)", "c(5)", "d(3)", "e(2)"], dependencies = ["a(b)", "e(c)"]
输出: ["b", "e", "a", "d", "c"]
Java 源码:
java
import java.util.*;
public class TaskScheduler {
private Map<String, Integer> taskTime;
private Map<String, List<String>> dependencies;
private Queue<String> queue;
public List<String> scheduleTasks(String[] tasks, String[] dependencies) {
taskTime = new HashMap<>();
for (String task : tasks) {
String[] parts = task.split("\\(");
taskTime.put(parts[0], Integer.parseInt(parts[1]));
}
this.dependencies = new HashMap<>();
for (String dep : dependencies) {
String[] parts = dep.split("(?=\\()");
this.dependencies.put(parts[0], parts[1]);
}
queue = new LinkedList<>();
for (String task : taskTime.keySet()) {
if (!dependencies.containsKey(task)) {
queue.add(task);
}
}
while (!queue.isEmpty()) {
String task = queue.poll();
if (taskTime.containsKey(task)) {
for (String nextTask : taskTime.keySet()) {
if (dependencies.get(nextTask).equals(task)) {
taskTime.remove(nextTask);
if (taskTime.size() == 1) {
return Arrays.asList(task);
}
for (String t : taskTime.keySet()) {
if (!queue.contains(t)) {
queue.add(t);
}
}
}
}
}
}
return Collections.emptyList();
}
public static void main(String[] args) {
TaskScheduler solution = new TaskScheduler();
String[] tasks = {"a(2)", "b(1)", "c(5)", "d(3)", "e(2)"};
String[] dependencies = {"a(b)", "e(c)"};
List<String> result = solution.scheduleTasks(tasks, dependencies);
System.out.println("Task order: " + result);
}
}
题目 3:活动选择问题
描述 :
给定一系列活动和它们的开始时间及结束时间,选择最大的活动集合,其中活动之间不会相互重叠。每次选择一个活动时,都必须在开始时间早于结束时间的前提下,选择结束时间最早的活动。
示例:
输入: [[1, 2], [3, 4], [2, 6]]
输出: [2, 3] 或 [3, 4]
Java 源码:
java
import java.util.*;
public class ActivitySelection {
public int[][] maxActivities(int[][]活动时间) {
Arrays.sort(活动时间, (a, b) -> a[1] - b[1]); // 按结束时间排序
int n =活动时间.length;
int[] dp = new int[n];
int[] prev = new int[n];
int count = 1;
dp[0] = 1;
prev[0] = -1;
for (int i = 1; i < n; i++) {
if (活动时间[i][0] >= dp[i - 1]) {
// 如果当前活动的开始时间大于等于上一个活动的结束时间,则选择
dp[i] = dp[i - 1] + 1;
prev[i] = i - 1;
} else {
dp[i] = dp[i - 1];
prev[i] = prev[i - 1];
}
if (dp[i] > count) {
count = dp[i];
}
}
int[] result = new int[count];
for (int i = 0; i < count; i++) {
result[i] =活动时间[prev[n - 1 - i]][0];
}
return new int[][]{{result[0], dp[n - 1]}, {活动时间[prev[n - 1]][0], dp[n - 1]}};
}
public static void main(String[] args) {
ActivitySelection solution = new ActivitySelection();
int[][] 活动时间 = {{1, 2}, {3, 4}, {2, 6}};
int[][] result = solution.maxActivities(活动时间);
System.out.println("Max activities: " + Arrays.deepToString(result));
}
}
这些题目和源码展示了拓扑排序在解决实际问题中的应用。在面试中,能够根据问题的特点选择合适的算法并实现其解决方案是非常重要的。希望这些示例能够帮助你更好地准备面试!在大厂面试中,与强连通分量(SCC)相关的问题通常涉及到图论和算法设计。以下是三道可能出现在大厂面试中的编程题目,以及相应的Java源码实现。
题目 1:课程完成顺序
描述 :
给定一个课程之间的先修课程列表,每个课程都有一个先修课程和对应的课程编号。如果学生要完成所有课程,确定一个课程完成的顺序。如果不可能完成所有课程,则返回空列表。
示例:
输入: [["a", "b"], ["c", "d"], ["b", "c"], ["d", "a"]]
输出: ["d", "c", "b", "a"] 或其他有效的顺序
Java 源码:
java
import java.util.*;
public class CourseCompletionOrder {
private Map<String, List<String>> prerequisites;
private Set<String> visited;
private List<String> order;
public List<String> findOrder(String[] courses, String[][] prerequisites) {
this.prerequisites = new HashMap<>();
this.visited = new HashSet<>();
this.order = new ArrayList<>();
for (String[] course : prerequisites) {
this.prerequisites.put(course[1], new ArrayList<>());
}
for (String[] course : prerequisites) {
this.prerequisites.get(course[1]).add(course[0]);
}
for (String course : courses) {
if (!visited.contains(course)) {
dfs(course);
}
}
return order.isEmpty() ? Collections.emptyList() : order;
}
private void dfs(String course) {
visited.add(course);
for (String preCourse : prerequisites.get(course)) {
if (!visited.contains(preCourse)) {
dfs(preCourse);
}
}
order.add(0, course); // 逆序添加到列表中以保持完成顺序
}
public static void main(String[] args) {
CourseCompletionOrder solution = new CourseCompletionOrder();
String[] courses = {"a", "b", "c", "d"};
String[][] prerequisites = {{"a", "b"}, {"c", "d"}, {"b", "c"}, {"d", "a"}};
List<String> result = solution.findOrder(courses, prerequisites);
System.out.println("Course completion order: " + result);
}
}
题目 2:社交网络中的强关系
描述 :
给定一个社交网络的联系列表,每个用户都有一个或多个朋友。定义一个强关系为如果 A 是 B 的朋友,B 也是 A 的朋友。找出社交网络中的所有强关系组。
示例:
输入: friendships = [["alice", "bob"], ["bob", "carol"], ["alice", "carol"]]
输出: [["alice", "bob", "carol"]]
Java 源码:
java
import java.util.*;
public class StrongRelationships {
private Map<String, List<String>> friendships;
public List<List<String>> findStrongRelationships(String[][] friendships) {
this.friendships = new HashMap<>();
for (String[] friendship : friendships) {
if (!this.friendships.containsKey(friendship[0])) {
this.friendships.put(friendship[0], new ArrayList<>());
}
this.friendships.get(friendship[0]).add(friendship[1]);
if (!this.friendships.containsKey(friendship[1])) {
this.friendships.put(friendship[1], new ArrayList<>());
}
this.friendships.get(friendship[1]).add(friendship[0]);
}
List<List<String>> strongRelationships = new ArrayList<>();
for (List<String> group : friendships.values()) {
if (group.size() > 1) {
strongRelationships.add(new ArrayList<>(group));
}
}
return strongRelationships;
}
public static void main(String[] args) {
StrongRelationships solution = new StrongRelationships();
String[][] friendships = {{"alice", "bob"}, {"bob", "carol"}, {"alice", "carol"}};
List<List<String>> result = solution.findStrongRelationships(friendships);
System.out.println("Strong relationships: " + result);
}
}
题目 3:网络中的强连通区域
描述 :
给定一个网络的连接列表,网络中的每个节点都可能存在多个连接。找出网络中的所有强连通区域。
示例:
输入: connections = [[1, 2], [2, 3], [3, 1], [4, 5]]
输出: [[1, 2, 3], [4, 5]]
Java 源码:
java
import java.util.*;
public class StronglyConnectedRegions {
private class Node {
int value;
List<Node> neighbors;
public Node(int value) {
this.value = value;
this.neighbors = new ArrayList<>();
}
}
public List<List<Integer>> findStronglyConnectedRegions(int[][] connections) {
Map<Integer, Node> nodes = new HashMap<>();
List<List<Integer>> regions = new ArrayList<>();
for (int[] connection : connections) {
Node u = nodes.getOrDefault(connection[0], new Node(connection[0]));
Node v = nodes.getOrDefault(connection[1], new Node(connection[1]));
u.neighbors.add(v);
nodes.put(u.value, u);
nodes.put(v.value, v);
}
Set<Integer> visited = new HashSet<>();
for (Node node : nodes.values()) {
if (!visited.contains(node.value)) {
dfs(node, regions);
}
}
return regions;
}
private void dfs(Node node, List<List<Integer>> regions) {
visited.add(node.value);
List<Integer> region = new ArrayList<>();
region.add(node.value);
for (Node neighbor : node.neighbors) {
if (!visited.contains(neighbor.value)) {
dfs(neighbor, regions);
}
}
if (!region.isEmpty()) {
regions.add(region);
}
}
public static void main(String[] args) {
StronglyConnectedRegions solution = new StronglyConnectedRegions();
int[][] connections = {{1, 2}, {2, 3}, {3, 1}, {4, 5}};
List<List<Integer>> result = solution.findStronglyConnectedRegions(connections);
System.out.println("Strongly connected regions: " + result);
}
}
这些题目和源码展示了强连通分量在不同场景下的应用。在面试中,能够根据问题的特点选择合适的算法并实现其解决方案是非常重要的。希望这些示例能够帮助你更好地准备面试!