LeetCode 2097. 合法重新排列数对

LeetCode 2097. 合法重新排列数对

题目描述

给你一个下标从 0 开始的二维整数数组 pairs,其中 pairs[i] = [start_i, end_i]。如果 pairs 的一个重新排列,满足对每一个下标 i1 <= 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)\)

欧拉路径与欧拉回路性质回顾:

  1. 对于无向图,所有边都是连通的。
    • 存在欧拉路径的充分必要条件:度数为奇数的点只能有0或2个
    • 存在欧拉回路的充分必要条件:度数为奇数的点只能有0个
  2. 对于有向图,所有边都是连通。
    • 存在欧拉路径的充分必要条件:要么所有点的出度均等于入度;要么除了两个点之外,其余所有点的出度等于入度,剩余的两个点:一个满足出度比入度多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;
    }
};
posted @ 2021-12-09 20:17  pxlsdz  阅读(210)  评论(0编辑  收藏  举报