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;
}
};