leetcode
leetcode 2301 ~ 2350
找到两个数组的前缀公共数组

找到两个数组的前缀公共数组

难度:

标签:

题目描述

You are given two 0-indexed integer permutations A and B of length n.

A prefix common array of A and B is an array C such that C[i] is equal to the count of numbers that are present at or before the index i in both A and B.

Return the prefix common array of A and B.

A sequence of n integers is called a permutation if it contains all integers from 1 to n exactly once.

 

Example 1:

Input: A = [1,3,2,4], B = [3,1,2,4]
Output: [0,2,3,4]
Explanation: At i = 0: no number is common, so C[0] = 0.
At i = 1: 1 and 3 are common in A and B, so C[1] = 2.
At i = 2: 1, 2, and 3 are common in A and B, so C[2] = 3.
At i = 3: 1, 2, 3, and 4 are common in A and B, so C[3] = 4.

Example 2:

Input: A = [2,3,1], B = [3,1,2]
Output: [0,1,3]
Explanation: At i = 0: no number is common, so C[0] = 0.
At i = 1: only 3 is common in A and B, so C[1] = 1.
At i = 2: 1, 2, and 3 are common in A and B, so C[2] = 3.

 

Constraints:

  • 1 <= A.length == B.length == n <= 50
  • 1 <= A[i], B[i] <= n
  • It is guaranteed that A and B are both a permutation of n integers.

代码结果

运行时间: 33 ms, 内存: 16.0 MB


/*
题目思路:
1. 创建一个长度为 n 的结果数组 C。
2. 使用两个集合来跟踪 A 和 B 的前缀元素。
3. 遍历数组,比较当前索引之前的前缀元素,统计公共元素的数量并存储到 C 中。
*/

import java.util.*;
import java.util.stream.*;

public class Solution {
    public int[] findPrefixCommonArray(int[] A, int[] B) {
        int n = A.length;
        int[] C = new int[n];
        Set<Integer> setA = new HashSet<>();
        Set<Integer> setB = new HashSet<>();

        IntStream.range(0, n).forEach(i -> {
            setA.add(A[i]);
            setB.add(B[i]);
            C[i] = (int) setA.stream().filter(setB::contains).count();
        });
        return C;
    }
}

解释

方法:

题解的核心思路在于利用两个集合来跟踪数组A和B中已经见过的元素。对于每个索引i,我们检查数组A和B的当前元素是否已经在对方的集合中出现过。如果是,相应的计数器(count_A或count_B)增加。这两个计数器分别跟踪A的元素在B的前缀中出现的次数和B的元素在A的前缀中出现的次数。最后,将这两个计数器的和存储在结果数组的相应位置。这种方法确保了即便元素以不同的顺序出现,也能正确计算出前缀中共有元素的数量。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在实现中,为什么要分别使用两个计数器count_A和count_B来跟踪交叉出现的元素,而不是单一计数器?
在这个算法中,使用两个计数器count_A和count_B是为了独立跟踪数组A中的元素在数组B的前缀中出现的次数,以及数组B中的元素在数组A的前缀中出现的次数。这样做可以确保每个数组的元素在对方数组中的每一次出现都被正确计数,尤其是在处理前缀时,这一点尤为重要。使用单一计数器可能导致某些情况下的错误统计,例如一方的元素在另一方前缀中多次出现可能会被重复计数或遗漏。
🦆
如果数组A和B的长度不同或不是完全的排列(即含有重复元素或不包含1到n的所有整数),该算法是否仍然有效?
如果数组A和B的长度不同,当前算法将无法直接适用,因为它假设两个数组具有相同的长度n,并在同一循环中同时遍历这两个数组。此外,如果数组包含重复元素或不是从1到n的整数集,算法仍可以正确地计算交叉出现的次数,因为它是基于集合成员资格来判断元素是否已在另一数组的前缀中出现过。不过,对于不同长度的数组,需要调整算法以处理长度不一的情况,可能通过填充较短数组或修改循环逻辑来实现。
🦆
算法中的逻辑对于元素的出现顺序是否敏感?即如果两个数组元素相同但顺序完全相反,输出结果会有何不同?
算法对于元素的出现顺序是敏感的。因为算法是依赖于元素在数组中的位置来决定其是否已在对方数组的前缀中出现过。如果两个数组的元素相同但顺序完全相反,计数器的增加将在不同的时间点发生,因此输出的前缀公共数组将会不同。例如,如果一个数组是另一个数组的逆序,那么每次比较时,前缀交叉出现的情况将会更少,直到最后一个元素才可能出现最多的交叉点。
🦆
在题解中提到的集合seen_A和seen_B,当元素被添加进集合时,是否需要检查该元素之前是否已存在于集合中?
在题解中使用的集合seen_A和seen_B是为了跟踪已经在各自数组中出现过的元素,使用集合是因为集合自动处理重复元素的问题,即集合会忽略重复添加的元素。因此,当元素被添加到集合中时,不需要显式检查该元素是否已存在于集合中,因为如果元素已存在,集合不会再次添加它。这样可以保持代码的简洁性和效率。

相关问题