Medium
题目描述
给你一个整数 n 表示 n 支队伍。要求你生成一个赛程表,满足以下条件:
- 每支队伍与其他每支队伍都要比赛两次:一次主场,一次客场。
- 每天恰好有一场比赛;赛程表是连续天数的列表,
schedule[i]是第i天的比赛。 - 没有队伍在连续的两天比赛。
返回一个二维整数数组 schedule,其中 schedule[i][0] 表示主队,schedule[i][1] 表示客队。如果有多个满足条件的赛程表,返回其中任意一个。
如果不存在满足条件的赛程表,返回空数组。
示例 1:
输入:n = 3
输出:[]
解释:
由于每支队伍与其他每支队伍都要比赛两次,总共需要进行 6 场比赛:[0,1],[0,2],[1,2],[1,0],[2,0],[2,1]。
不可能创建一个赛程表而不让至少一支队伍在连续的两天比赛。
示例 2:
输入:n = 5
输出:[[0,1],[2,3],[0,4],[1,2],[3,4],[0,2],[1,3],[2,4],[0,3],[1,4],[2,0],[3,1],[4,0],[2,1],[4,3],[1,0],[3,2],[4,1],[3,0],[4,2]]
解释:
由于每支队伍与其他每支队伍都要比赛两次,总共需要进行 20 场比赛。
输出显示了满足条件的赛程表之一。没有队伍在连续的两天比赛。
约束条件:
2 <= n <= 50
解题思路
这道题需要为 n 支队伍安排赛程,确保每支队伍都与其他队伍比赛两次(主客场各一次),且没有队伍连续两天比赛。
关键分析:
- 总比赛场次为
n*(n-1)场 - 每天最多安排
n/2场比赛(每支队伍最多参与一场) - 当 n 为奇数时,每天只能安排
(n-1)/2场比赛,因为必有一支队伍轮空
解题思路:
- 可行性判断:当 n 为奇数且 n ≤ 3 时无解,因为比赛天数过少,无法满足不连续比赛的约束
- 贪心策略:优先选择剩余比赛场次最多的队伍进行配对,同时确保这些队伍在前一天没有比赛
- 状态维护:
- 追踪每对队伍之间的剩余比赛次数
- 记录每支队伍的总剩余比赛次数
- 记录上一天参与比赛的队伍
算法流程: 每一天贪心地选择可用队伍中剩余比赛最多的一对进行配对,直到所有比赛安排完毕。如果某天无法找到合适的配对(避免连续比赛),则无解。
这种贪心策略能够有效平衡各队伍的比赛分布,避免某些队伍过早完成所有比赛而导致后续无法配对的情况。
代码实现
class Solution {
public:
vector<vector<int>> generateSchedule(int n) {
if (n % 2 == 1 && n <= 3) return {};
// remaining[i][j] = number of remaining games between team i and j
vector<vector<int>> remaining(n, vector<int>(n, 2));
for (int i = 0; i < n; i++) {
remaining[i][i] = 0;
}
// total remaining games for each team
vector<int> totalRemaining(n, 2 * (n - 1));
vector<vector<int>> schedule;
vector<bool> playedYesterday(n, false);
int totalGames = n * (n - 1);
while (schedule.size() < totalGames) {
vector<pair<int, int>> todaysMatches;
vector<bool> playedToday(n, false);
// Find the best match for today
pair<int, int> bestMatch = {-1, -1};
int maxSum = -1;
for (int i = 0; i < n; i++) {
if (playedYesterday[i] || playedToday[i]) continue;
for (int j = i + 1; j < n; j++) {
if (playedYesterday[j] || playedToday[j]) continue;
if (remaining[i][j] > 0) {
int sum = totalRemaining[i] + totalRemaining[j];
if (sum > maxSum) {
maxSum = sum;
bestMatch = {i, j};
}
}
}
}
if (bestMatch.first == -1) {
return {}; // No valid schedule
}
int home = bestMatch.first;
int away = bestMatch.second;
// Decide who plays at home (alternate or prefer the one with more remaining games)
if (totalRemaining[away] > totalRemaining[home]) {
swap(home, away);
}
schedule.push_back({home, away});
remaining[home][away]--;
totalRemaining[home]--;
totalRemaining[away]--;
playedToday[home] = true;
playedToday[away] = true;
// Update played yesterday
playedYesterday = playedToday;
}
return schedule;
}
};
class Solution:
def generateSchedule(self, n: int) -> List[List[int]]:
if n % 2 == 1 and n <= 3:
return []
# remaining[i][j] = number of remaining games between team i and j
remaining = [[2 if i != j else 0 for j in range(n)] for i in range(n)]
# total remaining games for each team
total_remaining = [2 * (n - 1) for _ in range(n)]
schedule = []
played_yesterday = [False] * n
total_games = n * (n - 1)
while len(schedule) < total_games:
played_today = [False] * n
# Find the best match for today
best_match = (-1, -1)
max_sum = -1
for i in range(n):
if played_yesterday[i] or played_today[i]:
continue
for j in range(i + 1, n):
if played_yesterday[j] or played_today[j]:
continue
if remaining[i][j] > 0:
sum_remaining = total_remaining[i] + total_remaining[j]
if sum_remaining > max_sum:
max_sum = sum_remaining
best_match = (i, j)
if best_match[0] == -1:
return [] # No valid schedule
home, away = best_match
# Decide who plays at home (prefer the one with more remaining games)
if total_remaining[away] > total_remaining[home]:
home, away = away, home
schedule.append([home, away])
remaining[home][away] -= 1
total_remaining[home] -= 1
total_remaining[away] -= 1
played_today[home] = True
played_today[away] = True
# Update played yesterday
played_yesterday = played_today[:]
return schedule
public class Solution {
public int[][] GenerateSchedule(int n) {
if (n % 2 == 1 && n <= 3) return new int[0][];
// remaining[i][j] = number of remaining games between team i and j
int[,] remaining = new int[n, n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
remaining[i, j] = i == j ? 0 : 2;
}
}
// total remaining games for each team
int[] totalRemaining = new int[n];
for (int i = 0; i < n; i++) {
totalRemaining[i] = 2 * (n - 1);
}
List<int[]> schedule = new List<int[]>();
bool[] playedYesterday = new bool[n];
int totalGames = n * (n - 1);
while (schedule.Count < totalGames) {
bool[] playedToday = new bool[n];
// Find the best match for today
int bestHome = -1, bestAway = -1;
int maxSum = -1;
for (int i = 0; i < n; i++) {
if (playedYesterday[i] || playedToday[i]) continue;
for (int j = i + 1; j < n; j++) {
if (playedYesterday[j] || playedToday[j]) continue;
if (remaining[i, j] > 0) {
int sum = totalRemaining[i] + totalRemaining[j];
if (sum > maxSum) {
maxSum = sum;
bestHome = i;
bestAway = j;
}
}
}
}
if (bestHome == -1) {
return new int[0][]; // No valid schedule
}
// Decide who plays at home (prefer the one with more remaining games)
if (totalRemaining[bestAway] > totalRemaining[bestHome]) {
int temp = bestHome;
bestHome = bestAway;
bestAway = temp;
}
schedule.Add(new int[] { bestHome, bestAway });
remaining[bestHome, bestAway]--;
totalRemaining[bestHome]--;
totalRemaining[bestAway]--;
playedToday[bestHome] = true;
playedToday[bestAway] = true;
// Update played yesterday
playedYesterday = (bool[])playedToday.Clone();
}
return schedule.ToArray();
}
}
/**
* @param {number} n
* @return {number[][]}
*/
var generateSchedule = function(n) {
if (n % 2 === 1) return [];
const schedule = [];
const totalRounds = 2 * (n - 1);
for (let round = 0; round < totalRounds; round++) {
const matches = [];
for (let i = 0; i < n / 2; i++) {
let home, away;
if (i === 0) {
home = 0;
away = round % (n - 1) + 1;
} else {
const pos1 = (round - i) % (n - 1);
const pos2 = (round + i) % (n - 1);
home = pos1 === 0 ? n - 1 : pos1;
away = pos2 === 0 ? n - 1 : pos2;
}
if (round >= n - 1) {
[home, away] = [away, home];
}
matches.push([home, away]);
}
schedule.push(...matches);
}
return schedule;
};
复杂度分析
| 复杂度类型 | 值 |
|---|---|
| 时间复杂度 | O(n⁴) |
| 空间复杂度 | O(n²) |
说明:
- 时间复杂度:需要安排 n(n-1) 场比赛,每场比赛需要遍历 O(n²) 对队伍找到最佳配对,总体为 O(n⁴)
- 空间复杂度:需要 O(n²) 的二维数组存储队伍间的剩余比赛次数,以及 O(n) 的辅助数组
相关题目
- . Task Scheduler (Medium)