2657. 找到两个数组的前缀公共数组 | 难度:中等

2657. 找到两个数组的前缀公共数组 | 难度:中等

题意理解(用样例说话)

题目给定两个排列 A 和 B(长度都是 n,包含 1 到 n 的每个数字恰好一次),要求我们计算「前缀公共数组」C。

关键定义 :C[i] 表示在 A 和 B 的前 i+1 个元素中 (即下标 0 到 i),同时出现在两个数组前缀中的不同元素个数

用题目示例 A = [1, 3, 2, 4], B = [3, 1, 2, 4] 演示:

下标 i A 的前缀 B 的前缀 公共元素 C[i]
0 [1] [3] 0
1 [1, 3] [3, 1] {1, 3} 2
2 [1, 3, 2] [3, 1, 2] {1, 2, 3} 3
3 [1, 3, 2, 4] [3, 1, 2, 4] {1, 2, 3, 4} 4

输出[0, 2, 3, 4]


解法思路

核心观察

由于 A 和 B 都是排列,每个数字只会出现一次。因此,当我们遍历到下标 i 时:

  • 如果某个数字 x 既出现在 A[0...i] 中,又出现在 B[0...i] 中,那么 x 必然会被计入 C[i]。

直观做法:双哈希集

我们可以用两个哈希集分别记录 A 和 B 的前缀元素,然后用第三个哈希集记录它们的交集。

具体步骤

  1. 初始化三个无序集合:cntA(记录 A 的前缀元素)、cntB(记录 B 的前缀元素)、cnt(记录公共元素)
  2. 遍历下标 i 从 0 到 n-1:
    • 将 A[i] 插入 cntA
    • 将 B[i] 插入 cntB
    • 关键 :检查 A[i] 是否已经在 cntB 中(说明 A[i] 是公共元素)
    • 关键 :检查 B[i] 是否已经在 cntA 中(说明 B[i] 是公共元素)
    • 如果满足,将该元素加入 cnt
    • 记录 cnt.size() 到答案数组

为什么这个方法正确?

  • 由于是排列,每个数字只会出现一次,所以我们不需要计数,只需要知道「是否出现过」
  • 当我们处理下标 i 时,cntAcntB 中分别记录了 A[0...i] 和 B[0...i] 的所有元素
  • 如果 A[i] 在 cntB 中,说明 A[i] 也出现在 B 的前缀中,因此它是公共元素
  • 同理适用于 B[i]

代码实现

参考你提供的代码,我们可以这样实现(添加了详细注释):

cpp 复制代码
class Solution {
public:
    vector<int> findThePrefixCommonArray(vector<int>& A, vector<int>& B) {
        int n = A.size();
        unordered_set<int> cntA, cntB;  // 分别记录 A 和 B 的前缀元素
        unordered_set<int> cnt;           // 记录当前位置的公共元素
        vector<int> ans;

        for (int i = 0; i < n; i++) {
            // 将当前元素加入各自的前缀集合
            cntA.emplace(A[i]);
            cntB.emplace(B[i]);

            // 关键:检查 A[i] 是否也在 B 的前缀中出现过
            if (cntB.count(A[i])) {
                cnt.emplace(A[i]);  // A[i] 是公共元素
            }

            // 关键:检查 B[i] 是否也在 A 的前缀中出现过
            if (cntA.count(B[i])) {
                cnt.emplace(B[i]);  // B[i] 是公共元素
            }

            // 当前位置的公共元素个数
            ans.emplace_back(cnt.size());
        }

        return ans;
    }
};

复杂度分析

  • 时间复杂度:O(n) ------ 只需遍历一次数组,每次哈希集操作平均 O(1)
  • 空间复杂度:O(n) ------ 三个哈希集最多各存储 n 个元素

易错点

1. 不要重复计数

由于 A 和 B 都是排列,每个数字只会出现一次 。但需要注意:当 A[i] == B[i] 时,两个 if 语句都会尝试插入同一个数字到 cnt 中。不过由于 unordered_set 会自动去重,所以最终结果是正确的。

错误示例(虽然不影响结果,但逻辑冗余):

cpp 复制代码
// 如果写成这样,当 A[i] == B[i] 时会检查两次
if (cntB.count(A[i])) cnt.emplace(A[i]);
if (cntA.count(B[i])) cnt.emplace(B[i]);  // 当 A[i]==B[i] 时,这行是多余的检查

改进写法(可选):

cpp 复制代码
if (cntB.count(A[i])) cnt.emplace(A[i]);
if (A[i] != B[i] && cntA.count(B[i])) cnt.emplace(B[i]);  // 避免重复检查

不过原代码的写法更简洁,且 unordered_set::emplace 对于重复元素会自动忽略,所以两种写法都可以。

2. 理解「前缀」的定义

C[i] 计算的是到下标 i 之前(包括 i)的公共元素个数。有些同学会误解为「到下标 i 之前(不包括 i)」,从而导致 off-by-one 错误。


相关题目

  1. 349. 两个数组的交集 ------ 思路类似,都是用哈希集找公共元素
  2. 350. 两个数组的交集 II ------ 进阶版,需要考虑元素出现次数

希望这篇题解能帮助你理解这道题的核心思路!如果还有疑问,欢迎继续讨论 💬

相关推荐
索木木9 小时前
NCCL SHARP 和 TREE算法
java·服务器·算法
Raink老师10 小时前
【AI面试临阵磨枪-59】企业内部 AI 系统权限、数据隔离、审计设计
人工智能·面试·职场和发展
心中有国也有家10 小时前
hccl 架构拆解:昇腾集合通信库到底在做什么?
人工智能·经验分享·笔记·分布式·算法·架构
小O的算法实验室11 小时前
2026年MCS,Q-learning增强MOPSO与改进DWA融合算法+复杂三维地形下特定移动机器人动态路径规划
算法
JAVA社区11 小时前
Java进阶全套教程(四)—— SpringMVC框架详解
java·开发语言·spring·面试·职场和发展
Peter·Pan爱编程12 小时前
10. new_delete 不是 malloc_free 的包装
c++·人工智能·算法
dayuOK630712 小时前
从“爆款复刻”到“个性化创作”:AI辅助写作的技术挑战与演进方向
人工智能·职场和发展·自动化·新媒体运营·媒体
Raink老师13 小时前
【AI面试临阵磨枪-58】AI 生成内容合规、版权、审核机制设计
人工智能·面试·职场和发展
故事和你9113 小时前
洛谷-【动态规划1】动态规划的引入2
开发语言·数据结构·c++·算法·动态规划·图论