leetcode
leetcode 1801 ~ 1850
合法重新排列数对

合法重新排列数对

难度:

标签:

题目描述

代码结果

运行时间: 452 ms, 内存: 79.0 MB


/*
 * 思路:
 * 1. 将所有pair转换为Map。
 * 2. 使用Stream从任意一个pair开始查找下一个匹配的pair。
 * 3. 构建最终结果列表。
 */
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Solution {
    public List<int[]> validReorder(int[][] pairs) {
        // 将pair转换为Map
        Map<Integer, Integer> pairMap = Arrays.stream(pairs)
                .collect(Collectors.toMap(pair -> pair[0], pair -> pair[1]));

        // 使用Stream查找下一个匹配的pair
        List<int[]> result = new ArrayList<>();
        int[] current = pairs[0];
        result.add(current);
        while (pairMap.containsKey(current[1])) {
            current = new int[]{current[1], pairMap.get(current[1])};
            result.add(current);
        }

        return result;
    }
}

解释

方法:

题解利用了图的深度优先搜索(DFS)来找到一条合法的路径,使得每对数的第二个元素正好是下一对数的第一个元素。首先,构建一个图g,其中每个节点代表数对中的starti,每个节点指向endi。同时,计算每个节点的入度(indeg)。在选择起始点时,寻找一个节点的出度大于入度的节点作为起始节点(如果存在这样的节点,则意味着这是唯一的起点,否则任意节点均可)。然后从起始点开始使用DFS,每次访问一个节点并在访问后将其从图中删除,确保每个连接只被使用一次。访问的顺序被反转存储在结果数组中,因为DFS会首先到达深层节点,而我们需要的顺序是从起点开始的顺序。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在算法中,如何处理存在多个节点出度大于入度的情况?
在一个有效的重新排列问题中,理论上不会出现存在多个节点出度大于入度的情况,因为这将违反每对数的第二个元素正好是下一对数的第一个元素的规则。如果一个图中的节点出现出度大于入度的情况超过一个,则无法形成一个连续的路径。但是,如果确实发现多个这样的节点,在算法逻辑中通常会视为数据输入错误或者问题描述的特殊情况,需要额外的错误检查或特殊处理。
🦆
为什么在DFS完成后需要将结果数组反转,这里的逻辑是怎样的?
在DFS过程中,每次递归访问一个节点(从当前节点到下一个节点),我们会在DFS返回后将当前的数对添加到结果数组中。因此,最深的递归调用(最远的节点对)最先被添加到结果数组。这意味着结果数组中数对的顺序是从终点到起点的顺序。为了得到一个从起点到终点的路径,我们需要将数组反转,这样才能正确地按照题目要求输出从起始点开始的路径顺序。
🦆
题解中提到使用了`defaultdict`来构建图,请问为什么选择`defaultdict`而不是普通的字典?
在构建图时使用`defaultdict`可以简化代码,因为如果使用普通字典,在添加节点和边时需要先检查键是否存在,如果不存在则首先创建一个空列表。使用`defaultdict`,如果键不存在,它会自动为该键提供一个默认的空列表,从而避免了额外的键存在性检查,使得代码更简洁、更易于管理。
🦆
在DFS递归过程中,如果遇到一个已经访问过的节点会如何处理?题解中是否有防止重复访问的机制?
在此题解中,每次访问一个节点时,会从图中删除这个节点到其它节点的连接(使用`pop`操作)。这种方法确保了每个连接只被访问一次。因此,虽然DFS过程中可能会多次到达同一个节点,但每次到达时可用的连接都是不同的。这里没有显式的检查节点是否被访问过的机制,而是通过确保每个连接只使用一次来防止重复访问同一个路径。

相关问题