YTU 3723 快速找到和为零的四个数 哈希 unordered_map讲解

问题: 快速找到和为零的四个数

时间限制: 2.00s | 内存限制: 128MB

题目描述

定义求和问题如下:给定 4 组整数 A,B,C,D,找到有多少四元组 (a,b,c,d)∈A×B×C×D(a, b, c, d) , 满足条件a+b+c+d=0。此问题中,假设A,B,C,D 具有相同的大小 n。

输入

输入包含多组测试数据。每组测试数据的第一行包含一个整数 n,表示 A,B,C,D 的元素个数(n≤1000)。接下来 n 行每行 4 个整数,分别属于 A,B,C,D,每个整数的大小在 [−228,228]之间。

输出

对于每组测试数据,输出满足条件的四元组的个数。

输入输出样例

样例输入 #1

复制

6
-45 22 42 -16
-41 -27 56 30
-36 53 -37 77
-36 30 -75 -46
26 -38 -10 62
-32 -54 -6 45
样例输出 #1

复制

5

 unorder_map用法:

当我们需要键值对映射起来,并且希望快速的通过键来寻找值时,unorder_map就是一种非常好用的数据结构,在C++标准库当中,unorder_map是一种哈希的表现,它提供了一种高效的方法来实现键值对的存储和检索。

unordered_map 的用法类似于普通的 map,但它的键值对没有按照特定的顺序进行排序。因此,在大多数情况下,unordered_map 的查找、插入和删除操作的时间复杂度都是常数时间 O(1),具有非常高的效率。

下面是一些 unordered_map 的基本操作

1.插入元素: 使用 insert() 函数或者下标操作符 [] 可以向 unordered_map 中插入新的键值对。如果键已经存在,则对应的值会被更新。

unordered_map<int, string> myMap;
myMap.insert({1, "apple"});
myMap[2] = "banana";

2.访问元素: 使用下标操作符 [] 或者 at() 函数可以通过键来访问对应的值。

cout << myMap[1] << endl;  // 输出 "apple"
cout << myMap.at(2) << endl;  // 输出 "banana"

3.查找元素: 使用 find() 函数可以根据键查找对应的值。如果键存在,则返回指向该键值对的迭代器,否则返回 end()
 

auto it = myMap.find(1);
if (it != myMap.end()) {
    cout << "Key found, value is: " << it->second << endl;
} else {
    cout << "Key not found!" << endl;
}

4.删除元素: 使用 erase() 函数可以根据键删除对应的键值对。

myMap.erase(1);  // 删除键为 1 的键值对

总的来说,unordered_map 是一个非常方便和高效的数据结构,特别适用于需要快速查找键值对的情况。


思路:

我们首先创建了一个 unordered_map<int, int> 类型的哈希表 sumAB,用于存储数组A和B的元素之和以及对应的出现次数。然后,我们使用两层循环遍历数组A和B,将它们的元素之和作为键,在哈希表中对应的值加一。

接下来,我们再次使用两层循环遍历数组C和D,计算目标值(即C[i] + D[j] 的相反数)。然后,在哈希表 sumAB 中查找是否存在对应的键,如果存在,则将对应键的值累加到计数器 count 上。

最后,输出 count 的值,即为满足条件的四元组个数。

代码实现:
 

#include <iostream>
#include <vector>
#include <unordered_map>

using namespace std;

int main()
{
    int n;
    while (cin >> n) // 读取输入的大小 n
    {
        // 创建四个大小为 n 的动态数组 A、B、C、D
        vector<int> A(n), B(n), C(n), D(n);
        
        // 读取输入的四个数组 A、B、C、D
        for (int i = 0; i < n; ++i)
        {
            cin >> A[i] >> B[i] >> C[i] >> D[i];
        }

        // 计算 A 和 B 数组元素之和的出现次数,并存储到 sumAB 中
        unordered_map<int, int> sumAB;
        for (int i = 0; i < n; ++i)
        {
            for (int j = 0; j < n; ++j)
            {
                sumAB[A[i] + B[j]]++; // 计算 A[i] + B[j] 的和,如果和已存在,则增加其出现次数;否则插入新的键值对
            }
        }

        int count = 0;
        // 遍历 C 和 D 数组元素,查找与其和为负的 A 和 B 数组元素之和的次数
        for (int i = 0; i < n; ++i)
        {
            for (int j = 0; j < n; ++j)
            {
                int target = -(C[i] + D[j]); // 计算目标值为 -(C[i] + D[j])
                if (sumAB.find(target) != sumAB.end()) // 在 sumAB 中查找目标值,如果找到则累加其出现次数到 count 中
                {
                    count += sumAB[target];
                }
            }
        }

        // 输出结果
        cout << count << endl;
    }
    return 0;
}

  • 16
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值