给定条件下构造矩阵
难度:
标签:
题目描述
给你一个 正 整数 k
,同时给你:
- 一个大小为
n
的二维整数数组rowConditions
,其中rowConditions[i] = [abovei, belowi]
和 - 一个大小为
m
的二维整数数组colConditions
,其中colConditions[i] = [lefti, righti]
。
两个数组里的整数都是 1
到 k
之间的数字。
你需要构造一个 k x k
的矩阵,1
到 k
每个数字需要 恰好出现一次 。剩余的数字都是 0
。
矩阵还需要满足以下条件:
- 对于所有
0
到n - 1
之间的下标i
,数字abovei
所在的 行 必须在数字belowi
所在行的上面。 - 对于所有
0
到m - 1
之间的下标i
,数字lefti
所在的 列 必须在数字righti
所在列的左边。
返回满足上述要求的 任意 矩阵。如果不存在答案,返回一个空的矩阵。
示例 1:
输入:k = 3, rowConditions = [[1,2],[3,2]], colConditions = [[2,1],[3,2]] 输出:[[3,0,0],[0,0,1],[0,2,0]] 解释:上图为一个符合所有条件的矩阵。 行要求如下: - 数字 1 在第 1 行,数字 2 在第 2 行,1 在 2 的上面。 - 数字 3 在第 0 行,数字 2 在第 2 行,3 在 2 的上面。 列要求如下: - 数字 2 在第 1 列,数字 1 在第 2 列,2 在 1 的左边。 - 数字 3 在第 0 列,数字 2 在第 1 列,3 在 2 的左边。 注意,可能有多种正确的答案。
示例 2:
输入:k = 3, rowConditions = [[1,2],[2,3],[3,1],[2,3]], colConditions = [[2,1]] 输出:[] 解释:由前两个条件可以得到 3 在 1 的下面,但第三个条件是 3 在 1 的上面。 没有符合条件的矩阵存在,所以我们返回空矩阵。
提示:
2 <= k <= 400
1 <= rowConditions.length, colConditions.length <= 104
rowConditions[i].length == colConditions[i].length == 2
1 <= abovei, belowi, lefti, righti <= k
abovei != belowi
lefti != righti
代码结果
运行时间: 68 ms, 内存: 22.9 MB
/*
* Problem: Construct a k x k matrix where each number from 1 to k appears exactly once
* and the matrix satisfies row and column conditions given by rowConditions and colConditions.
* Approach:
* 1. Use topological sorting to determine the order of numbers in rows and columns.
* 2. If there is a cycle detected during sorting, return an empty matrix.
* 3. Place the numbers in the matrix according to the determined row and column orders.
*/
import java.util.*;
import java.util.stream.*;
public class MatrixConstructor {
public int[][] buildMatrix(int k, int[][] rowConditions, int[][] colConditions) {
int[][] result = new int[k][k];
int[] rowOrder = topologicalSort(k, rowConditions);
int[] colOrder = topologicalSort(k, colConditions);
if (rowOrder == null || colOrder == null) return new int[0][0];
Map<Integer, Integer> rowIndex = IntStream.range(0, k)
.boxed()
.collect(Collectors.toMap(i -> rowOrder[i], i -> i));
Map<Integer, Integer> colIndex = IntStream.range(0, k)
.boxed()
.collect(Collectors.toMap(i -> colOrder[i], i -> i));
IntStream.rangeClosed(1, k).forEach(i -> result[rowIndex.get(i)][colIndex.get(i)] = i);
return result;
}
private int[] topologicalSort(int k, int[][] conditions) {
int[] inDegree = new int[k + 1];
List<Integer>[] graph = Stream.generate(ArrayList<Integer>::new)
.limit(k + 1)
.toArray(ArrayList[]::new);
Arrays.stream(conditions).forEach(cond -> {
graph[cond[0]].add(cond[1]);
inDegree[cond[1]]++;
});
Queue<Integer> queue = IntStream.rangeClosed(1, k)
.filter(i -> inDegree[i] == 0)
.boxed()
.collect(Collectors.toCollection(LinkedList::new));
int[] order = new int[k];
int index = 0;
while (!queue.isEmpty()) {
int node = queue.poll();
order[index++] = node;
graph[node].forEach(neighbor -> {
if (--inDegree[neighbor] == 0) queue.offer(neighbor);
});
}
return index == k ? order : null;
}
}
解释
方法:
题解的核心思想是使用拓扑排序来确定行和列的相对顺序。首先,将 `rowConditions` 和 `colConditions` 分别视为有向图中的边,构建两个图:一个用于行的约束,另一个用于列的约束。然后对这两个图进行拓扑排序。如果图中存在环(即拓扑排序返回空),则说明没有合法的布局满足所有条件,返回空矩阵。如果排序成功,使用排序结果来构建矩阵,其中行排序结果决定数字在矩阵中的行,列排序结果决定数字在矩阵中的列。最后,根据这两个结果构建最终的矩阵。
时间复杂度:
O(k^2 + n + m)
空间复杂度:
O(k^2 + n + m)
代码细节讲解
🦆
如何确保构建的两个有向图完全表达了rowConditions和colConditions中的所有约束关系?
▷🦆
在拓扑排序中,如果存在环,解题思路中提到返回空矩阵。请问如何有效地检测这些图中是否存在环?
▷🦆
在拓扑排序后如何处理多个有效排序结果?解题思路是否考虑了不同拓扑排序结果对最终矩阵的影响?
▷🦆
题解中提到使用字典`mp`来映射列位置,这种映射方式是否可能导致某些数字在矩阵中的位置不符合初始的colConditions约束?
▷