Medium

题目描述

有一个由 n 个不同元素组成的整数数组 nums,但是你已经忘记了它。不过,你还记得 nums 中每一对相邻元素。

给你一个二维整数数组 adjacentPairs,大小为 n - 1,其中每个 adjacentPairs[i] = [ui, vi] 表示元素 ui 和 vi 在 nums 中相邻。

题目数据保证所有由元素 nums[i] 和 nums[i+1] 组成的相邻元素对都存在于 adjacentPairs 中,存在形式可能是 [nums[i], nums[i+1]],也可能是 [nums[i+1], nums[i]]。这些相邻元素对可以按任意顺序出现。

返回原始数组 nums。如果存在多种解答,返回其中任意一个即可。

示例 1:

输入:adjacentPairs = [[2,1],[3,4],[3,2]]
输出:[1,2,3,4]
解释:数组中所有相邻元素对都在 adjacentPairs 中。
注意到 adjacentPairs[i] 中的元素顺序可能不是从左到右的。

示例 2:

输入:adjacentPairs = [[4,-2],[1,4],[-3,1]]
输出:[-2,4,1,-3]
解释:数组中可以存在负数。
另一个解答是 [-3,1,4,-2] ,也会被接受。

示例 3:

输入:adjacentPairs = [[100000,-100000]]
输出:[100000,-100000]

约束条件:

  • nums.length == n
  • adjacentPairs.length == n - 1
  • adjacentPairs[i].length == 2
  • 2 <= n <= 10^5
  • -10^5 <= nums[i], ui, vi <= 10^5
  • 存在一些 nums 使得 adjacentPairs 为其相邻元素对。

解题思路

这道题本质上是将相邻对重构成一个链表(或者说一条链)。我们可以将其建模为一个图问题来解决。

解题思路

  1. 构建图结构:将每个相邻对看作图中的一条边,构建邻接表。每个元素最多有2个邻居(除了两端的元素)。

  2. 找到起点:在一条链中,两端的元素只有1个邻居,而中间的元素有2个邻居。因此我们可以通过统计每个元素的邻居数量来找到起点(或终点)。

  3. 深度优先搜索:从起点开始,使用DFS遍历整条链。为了避免回头,我们需要记录上一个访问的元素,确保不会重复访问。

算法步骤

  1. 遍历所有相邻对,构建哈希表记录每个元素的所有邻居
  2. 找到只有一个邻居的元素作为起点(链的一端)
  3. 从起点开始DFS,每次选择一个未访问过的邻居继续遍历
  4. 将遍历路径记录为结果数组

时间复杂度为O(n),空间复杂度为O(n),其中n为数组长度。

代码实现

class Solution {
public:
    vector<int> restoreArray(vector<vector<int>>& adjacentPairs) {
        unordered_map<int, vector<int>> graph;
        
        // 构建邻接表
        for (auto& pair : adjacentPairs) {
            graph[pair[0]].push_back(pair[1]);
            graph[pair[1]].push_back(pair[0]);
        }
        
        // 找到起点(只有一个邻居的元素)
        int start = 0;
        for (auto& [node, neighbors] : graph) {
            if (neighbors.size() == 1) {
                start = node;
                break;
            }
        }
        
        vector<int> result;
        int prev = INT_MAX; // 用于记录上一个访问的节点
        
        function<void(int)> dfs = [&](int curr) {
            result.push_back(curr);
            for (int next : graph[curr]) {
                if (next != prev) {
                    prev = curr;
                    dfs(next);
                    break;
                }
            }
        };
        
        dfs(start);
        return result;
    }
};
class Solution:
    def restoreArray(self, adjacentPairs: List[List[int]]) -> List[int]:
        from collections import defaultdict
        
        # 构建邻接表
        graph = defaultdict(list)
        for u, v in adjacentPairs:
            graph[u].append(v)
            graph[v].append(u)
        
        # 找到起点(只有一个邻居的元素)
        start = None
        for node, neighbors in graph.items():
            if len(neighbors) == 1:
                start = node
                break
        
        result = []
        prev = None
        
        def dfs(curr):
            nonlocal prev
            result.append(curr)
            for next_node in graph[curr]:
                if next_node != prev:
                    prev = curr
                    dfs(next_node)
                    break
        
        dfs(start)
        return result
public class Solution {
    public int[] RestoreArray(int[][] adjacentPairs) {
        var graph = new Dictionary<int, List<int>>();
        
        // 构建邻接表
        foreach (var pair in adjacentPairs) {
            if (!graph.ContainsKey(pair[0])) {
                graph[pair[0]] = new List<int>();
            }
            if (!graph.ContainsKey(pair[1])) {
                graph[pair[1]] = new List<int>();
            }
            graph[pair[0]].Add(pair[1]);
            graph[pair[1]].Add(pair[0]);
        }
        
        // 找到起点(只有一个邻居的元素)
        int start = 0;
        foreach (var kvp in graph) {
            if (kvp.Value.Count == 1) {
                start = kvp.Key;
                break;
            }
        }
        
        var result = new List<int>();
        int prev = int.MaxValue;
        
        void Dfs(int curr) {
            result.Add(curr);
            foreach (int next in graph[curr]) {
                if (next != prev) {
                    prev = curr;
                    Dfs(next);
                    break;
                }
            }
        }
        
        Dfs(start);
        return result.ToArray();
    }
}
var restoreArray = function(adjacentPairs) {
    const graph = new Map();
    
    for (const [u, v] of adjacentPairs) {
        if (!graph.has(u)) graph.set(u, []);
        if (!graph.has(v)) graph.set(v, []);
        graph.get(u).push(v);
        graph.get(v).push(u);
    }
    
    let start;
    for (const [node, neighbors] of graph) {
        if (neighbors.length === 1) {
            start = node;
            break;
        }
    }
    
    const result = [start];
    let prev = null;
    let current = start;
    
    while (result.length < adjacentPairs.length + 1) {
        const neighbors = graph.get(current);
        const next = neighbors[0] === prev ? neighbors[1] : neighbors[0];
        result.push(next);
        prev = current;
        current = next;
    }
    
    return result;
};

复杂度分析

算法时间复杂度空间复杂度
哈希表 + DFSO(n)O(n)
  • 时间复杂度:O(n),需要遍历所有相邻对来构建图,然后进行一次DFS遍历
  • 空间复杂度:O(n),需要哈希表存储邻接表和递归调用栈的空间