leetcode
leetcode 1051 ~ 1100
等价多米诺骨牌对的数量

等价多米诺骨牌对的数量

难度:

标签:

题目描述

代码结果

运行时间: 28 ms, 内存: 22.9 MB


/*
 * Problem: Given a list of dominoes, find the number of pairs (i, j) such that dominoes[i] and dominoes[j] are equivalent.
 * Two dominoes [a, b] and [c, d] are equivalent if and only if (a == c and b == d) or (a == d and b == c).
 * 
 * Approach:
 * 1. Use Java Streams to count the frequency of each domino configuration. Normalize each domino to a consistent form (min, max).
 * 2. For each domino configuration, if the count is more than 1, calculate the number of valid pairs using the combination formula n * (n - 1) / 2.
 */
import java.util.*;
import java.util.stream.Collectors;

public class DominoPairsStream {
    public int numEquivDominoPairs(int[][] dominoes) {
        Map<String, Long> map = Arrays.stream(dominoes)
                .map(domino -> {
                    int a = domino[0];
                    int b = domino[1];
                    return a < b ? a + "," + b : b + "," + a;
                })
                .collect(Collectors.groupingBy(e -> e, Collectors.counting()));

        return map.values().stream()
                .filter(val -> val > 1)
                .mapToInt(val -> (int) (val * (val - 1) / 2))
                .sum();
    }
}

解释

方法:

本题目的主要思路是使用哈希表来统计每种多米诺骨牌出现的次数。首先,对于每一对多米诺骨牌 [x, y],为了避免旋转后的等价性问题,我们首先将每对多米诺骨牌按照元素大小排序,确保较小的数字总是在前。这样,每一对可以唯一地表示为两位数 val = min(x, y) * 10 + max(x, y)。利用一个长度为 100 的数组 num 来统计每种 val 的出现次数。对于每一对多米诺骨牌,如果它在之前已经出现过,那么它能与之前的每一对形成一个新的等价对。因此,每次遇到同样的 val,当前的等价对数就是 val 已经出现的次数,我们把这个数累加到结果 ret 中。随后,更新这个 val 的出现次数。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
在哈希表解法中,为什么选择将多米诺骨牌的数对转换成一个两位数来表示,而不是使用元组或其他数据结构直接存储?
将多米诺骨牌的数对转换成一个两位数进行表示的主要原因是为了简化查找和存储过程。使用两位数可以直接通过简单的数组索引来访问和记录每种组合的出现次数,这比使用哈希表或元组更为高效和直接。数组的访问时间复杂度为O(1),而哈希表虽然平均情况下也提供O(1)的访问时间,但在最坏情况下会退化到O(n)。此外,使用两位数可以避免哈希冲突并减少内存使用。
🦆
在计算两位数 val 时使用的公式 `val = min(x, y) * 10 + max(x, y)` 是否有可能造成不同的多米诺骨牌对应同一个 val 值?
使用公式 `val = min(x, y) * 10 + max(x, y)` 不会造成不同的多米诺骨牌对应同一个 val 值。这是因为,公式首先确定了较小的数字作为十位数,较大的数字作为个位数,确保了每个多米诺骨牌对都有一个唯一的表示。例如,无论是多米诺骨牌 [2, 5] 还是 [5, 2],它们都将被表示为 25,确保了表示的唯一性。
🦆
给定最大多米诺骨牌数为 40,000,数组长度为 100 用来记录所有可能的多米诺骨牌组合是否足够?存在溢出或冲突的可能吗?
数组长度为 100 是足够的,因为多米诺骨牌的每个数值最大为 9(通常情况下),因此使用前述公式 `val = min(x, y) * 10 + max(x, y)`,最大的 val 值为 99。这样的表示方法确保了所有可能的多米诺骨牌组合都能在数组长度为 100 的数组中得到记录,不会存在溢出或冲突的情况。
🦆
题解中提到每遇到一个已存在的 val 就将其出现次数加到结果中,这种方法是否考虑了多米诺骨牌之间的不同组合次数?例如同样的多米诺骨牌重复出现的情况。
这种方法确实考虑了多米诺骨牌之间的不同组合次数,包括同样的多米诺骨牌重复出现的情况。每次遇到一个多米诺骨牌对,算法通过将其转换成唯一的数值 val 并记录在数组中。如果同样的 val 再次出现,其对应的数组值(即之前出现的次数)就会被加到结果中。这意味着每个多米诺骨牌对的每一次出现都将与之前的每一次出现形成新的等价对,因此可以正确地计算出所有可能的等价多米诺骨牌对的总数。

相关问题