【888题秋招篇】剑指大厂offer第五题,带你用数据结构思维秒杀OPPO校招真题-严格递增三元组,斩获大厂年薪60wOffer

更多精彩内容

这里是带你游历编程世界的Dashcoding编程社,我是Dash/北航硕士/ICPC区域赛全国排名30+/给你呈现我们眼中的世界!

256题算法特训课,帮你斩获大厂60W年薪offer

原题

OPPO校招真题严格递增三元组

B站动画详解

问题分析

在这个问题中,我们需要找出所有满足条件的三元组 ( i , j , k ) (i, j, k) (i,j,k),使得 1 ≤ i < j < k ≤ n 1 \leq i < j < k \leq n 1i<j<kn 并且 a i = a k = a j + 1 a_i = a_k = a_j + 1 ai=ak=aj+1。这意味着在三个索引 i , j , k i, j, k i,j,k 中, a i a_i ai a k a_k ak 的值必须相同,而 a j a_j aj 的值比它们小 1。因此,我们需要找到符合这些条件的三元组并统计它们的数量。

由于 n n n 的最大值可以达到 1 0 5 10^5 105 a i a_i ai 的最大值可以达到 1 0 9 10^9 109,我们需要一个高效的算法来完成任务,直接使用三重循环的暴力方法会导致 O ( n 3 ) O(n^3) O(n3) 的复杂度,这在大规模数据下是不可行的。

思路分析

为了解决这个问题,我们可以考虑使用数据结构和遍历的方法来提高效率。我们可以遍历数组,同时维护两个哈希表:

  1. bk[x]:用于记录当前遍历到的元素中,值为 x x x 的元素的出现次数。这将帮助我们统计满足 a i = x a_i = x ai=x 的元素。

  2. sum[x+1]:用于记录当前遍历到的元素中,值为 x + 1 x + 1 x+1 的元素的出现次数。这个哈希表将帮助我们统计满足 a j = x a_j = x aj=x a k = x + 1 a_k = x+1 ak=x+1 的三元组数量。

具体步骤如下:

  1. 从左到右遍历数组。对于每个元素 x x x

    • 将当前的 b k [ x ] bk[x] bk[x] 值累加到 sum[x+1] 中。这一步表示:已经遍历过的元素中,值为 x x x 的元素可以和未来的某个值为 x + 1 x+1 x+1 的元素形成合法的三元组。
    • 更新 bk[x],即记录当前遍历到的值为 x x x 的元素出现的次数。
    • 将 sum[x] 中记录的值累加到答案中。这一步表示:当前的 x x x 可以作为合法的三元组中的 a k a_k ak,并且已经找到多少个合法的三元组。
  2. 最终结果就是所有合法三元组的数量。

算法实现

为了找到所有符合条件的三元组 ( i , j , k ) (i, j, k) (i,j,k),我们采用一种基于哈希表的遍历算法。该算法的核心思想是通过两次哈希表的更新和查询,快速统计出满足条件的三元组数量。

  1. 初始化两个哈希表:
  • bk:用于记录当前遍历到的元素中,值为 x x x 的元素的出现次数。
  • sum:用于记录当前遍历到的元素中,值为 x + 1 x+1 x+1
    的元素的出现次数,这将帮助我们在未来找到合法的三元组。
  1. 遍历数组:
  • 对于每个元素 x,首先更新 sum[x+1],使其累加 bk[x+1] 的值。bk[x+1] 代表的是在当前元素 x 之前出现的值为
    x + 1 x+1 x+1 的元素的数量。
  • 然后,将 bk[x] 中的值增加 1 1 1,表示当前遍历到的元素 x x x 的数量增加了一个。
  • 接下来,累加 sum[x]到答案 ans中,sum[x]` 中的值代表的是满足 a j = x a_j = x aj=x 且存在 a i = x + 1 a_i = x+1 ai=x+1 的合法三元组的数量。
  1. 输出结果:遍历完成后,ans 中的值就是满足条件的三元组数量。

代码详解

标准代码程序

C++代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;

ll ans, x;
map<int, ll> bk, sum;

int main() {
    int n;
    cin >> n;
    for(int i = 1; i <= n; i++) {
        cin >> x;
        sum[x + 1] += bk[x + 1];  // 更新sum[x+1],表示值为x+1的元素数量。
        bk[x]++;                   // 记录当前值x的出现次数。
        ans += sum[x];             // 统计合法三元组的数量。
    }
    cout << ans;
}


Java代码

import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        long ans = 0;
        Map<Integer, Long> bk = new HashMap<>();
        Map<Integer, Long> sum = new HashMap<>();
        for (int i = 1; i <= n; i++) {
            int x = sc.nextInt();
            sum.put(x + 1, sum.getOrDefault(x + 1, 0L) + bk.getOrDefault(x + 1, 0L));
            bk.put(x, bk.getOrDefault(x, 0L) + 1);
            ans += sum.getOrDefault(x, 0L);
        }
        System.out.println(ans);
    }
}


Python代码

n = int(input())
a = list(map(int, input().split()))

ans = 0
bk = {}
sum_map = {}

for x in a:
    sum_map[x + 1] = sum_map.get(x + 1, 0) + bk.get(x + 1, 0)
    bk[x] = bk.get(x, 0) + 1
    ans += sum_map.get(x, 0)

print(ans)


Javascript代码

const readline = require('readline');
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

rl.on('line', function(line) {
    if (!this.n) {
        this.n = parseInt(line.trim());
    } else {
        const a = line.trim().split(' ').map(Number);
        let ans = 0;
        const bk = new Map();
        const sum = new Map();

        a.forEach(x => {
            sum.set(x + 1, (sum.get(x + 1) || 0) + (bk.get(x + 1) || 0));
            bk.set(x, (bk.get(x) || 0) + 1);
            ans += sum.get(x) || 0;
        });

        console.log(ans);
        rl.close();
    }
});


复杂度分析

  • 时间复杂度:该算法的时间复杂度为 O ( n ) O(n) O(n),其中 n n n 是数组的长度。我们只需要遍历一次数组,并在每次遍历时进行常数时间的哈希表操作,因此整体复杂度为 O ( n ) O(n) O(n)

  • 空间复杂度:算法使用了两个哈希表 bksum,每个哈希表的最大空间复杂度为 O ( n ) O(n) O(n)。因此,总的空间复杂度也是 O ( n ) O(n) O(n)

总结

这个题目要求我们在一个长度为 n n n 的数组中,找到所有符合特定条件的三元组 ( i , j , k ) (i, j, k) (i,j,k),即 1 ≤ i < j < k ≤ n 1 \leq i < j < k \leq n 1i<j<kn a i = a k = a j + 1 a_i = a_k = a_j + 1 ai=ak=aj+1。为了高效地解决这个问题,我们采用了哈希表和一次遍历的算法来进行处理。

该算法通过两个哈希表来记录和统计符合条件的元素组合情况。我们依次遍历数组中的每个元素,通过更新哈希表中的计数信息,逐步累积得到最终满足条件的三元组数量。这个方法避免了暴力搜索所有可能的三元组,极大地提高了算法的效率。

  • 13
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值