LeetCode 2097. 合法重新排列数对
LeetCode 2097. 合法重新排列数对
题目描述
给你一个下标从 0 开始的二维整数数组 pairs
,其中 pairs[i] = [start_i, end_i]
。如果 pairs
的一个重新排列,满足对每一个下标 i
(1 <= i < pairs.length
)都有 end_{i-1} == start_{i}
,那么我们就认为这个重新排列是 pairs
的一个 合法重新排列。
请你返回 任意一个 pairs
的合法重新排列。
注意:数据保证至少存在一个 pairs
的合法重新排列。
样例
输入:pairs = [[5,1],[4,5],[11,9],[9,4]]
输出:[[11,9],[9,4],[4,5],[5,1]]
解释:
输出的是一个合法重新排列,因为每一个 end_{i-1} 都等于 start_{i}。
end0 = 9 == 9 = start1
end1 = 4 == 4 = start2
end2 = 5 == 5 = start3
输入:pairs = [[1,3],[3,2],[2,1]]
输出:[[1,3],[3,2],[2,1]]
解释:
输出的是一个合法重新排列,因为每一个 end_{i-1} 都等于 start_{i}。
end0 = 3 == 3 = start1
end1 = 2 == 2 = start2
重新排列后的数组 [[2,1],[1,3],[3,2]] 和 [[3,2],[2,1],[1,3]] 都是合法的。
示例 3:
输入:pairs = [[1,2],[1,3],[2,1]]
输出:[[1,2],[2,1],[1,3]]
解释:
输出的是一个合法重新排列,因为每一个 end_{i-1} 都等于 start_{i}。
end0 = 2 == 2 = start1
end1 = 1 == 1 = start2
限制
- 1
<= pairs.length <= 10^5
pairs[i].length == 2
0 <= start_i, end_i <= 10^9
start_i != end_i
pairs
中不存在一模一样的数对。- 至少 存在 一个合法的
pairs
重新排列。
算法
(有向图的欧拉路径) \(O(n)\)
欧拉路径与欧拉回路性质回顾:
- 对于无向图,所有边都是连通的。
- 存在欧拉路径的充分必要条件:度数为奇数的点只能有0或2个
- 存在欧拉回路的充分必要条件:度数为奇数的点只能有0个
- 对于有向图,所有边都是连通。
- 存在欧拉路径的充分必要条件:要么所有点的出度均等于入度;要么除了两个点之外,其余所有点的出度等于入度,剩余的两个点:一个满足出度比入度多1(起点),另一个满足入度比出度多1(终点)
- 存在欧拉回路的充分必要条件:所有点的出度均等于入度。
欧拉路径的遍历算法描述:
dfs(u){ while 从u的所有出边: 删边; dfs(v);//扩展 seq<-u;// 保存的是欧拉回路的倒序 }
最终 seq[]中存下的就是欧拉路径的倒序,为什么u再最后才加入?因为需要遍历完
u
的所有子节点才能把u压入进来,u是后面所有点的起点。有向图:
每用一条边 删掉
无向图:
每用一条边标记对应的反向边(XOR技巧)
a→b
b→a数组模拟连接表:编号成对的(0, 1) (2, 3)(4, 5)......,编号的0的反向边为0^1 = 1,编号的1的反向边为1^1 = 0, 编号2的反向边为2^1 = 3,编号的2的反向边为3^1 = 2 ......
即
i
的反向边为i^1
本题可以转化为输出整个有向图的欧拉路径,输入路径上的编号组成答案。
构图:对每个数对 \(e\_i = (x, y)\),构造一条有向边 \(x \to y\),属性为 \(i\)。注意需要离散化一下。
因为题意本身就有答案,起点的出度减入度等于 1 的点或者任意一点即可。从起点开始深度优先遍历整个图即可。
时间复杂度
- 遍历所有点和边一次,故总时间复杂度为 \(O(n)\)。
空间复杂度
- 需要 \(O(n)\) 的额外空间存储图,递归的系统栈,以及欧拉路相关的数据结构。
C++代码
const int N = 100005;
class Solution {
public:
vector<int> alls;
vector<pair<int, int>> g[N];
vector<int> path;
int deg[N];
void dfs(int u, int prev){
while(!g[u].empty()){
int v = g[u].back().first, e = g[u].back().second;
g[u].pop_back();
dfs(v, e);
}
if(prev != -1){
path.push_back(prev);
}
}
vector<vector<int>> validArrangement(vector<vector<int>>& pairs) {
for(auto x : pairs){
alls.push_back(x[0]);
alls.push_back(x[1]);
}
sort(alls.begin(), alls.end());
alls.erase(unique(alls.begin(), alls.end()), alls.end());
for(int i = 0; i < pairs.size(); i++){
int x = lower_bound(alls.begin(), alls.end(), pairs[i][0]) - alls.begin();
int y = lower_bound(alls.begin(), alls.end(), pairs[i][1]) - alls.begin();
g[x].push_back({y, i});
deg[x]++;
deg[y]--;
}
int first = 0;
for(int i = 0; i < alls.size(); i++){
if(deg[i] == 1){
first = i;
break;
}
}
dfs(first, -1);
vector<vector<int>> res;
for(int i = path.size() - 1; i >= 0; i--){
res.push_back(pairs[path[i]]);
}
return res;
}
};