目录
题目描述
给你四个整数数组 nums1
、nums2
、nums3
和 nums4
,数组长度都是 n
,请你计算有多少个元组 (i, j, k, l)
能满足:
0 <= i, j, k, l < n
nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
示例 1:
输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2] 输出:2 解释: 两个元组如下: 1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0 2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0
示例 2:
输入:nums1 = [0], nums2 = [0], nums3 = [0], nums4 = [0] 输出:1
提示:
n == nums1.length
n == nums2.length
n == nums3.length
n == nums4.length
1 <= n <= 200
-228 <= nums1[i], nums2[i], nums3[i], nums4[i] <= 228
解题思路
观察发现,如果可以找到两个数对(来自不同数组),它们的和互为相反数,那么它们就可以组成一个满足条件的四元组。因此,问题可以转化为:对于每一对来自nums1和nums2的数,找到多少对来自nums3和nums4的数,它们的和与这对数的和互为相反数。
1.使用哈希表
哈希表是一种以平均常数时间复杂度进行插入、删除和查找的数据结构。在这个问题中,可以使用哈希表来存储nums1和nums2中所有两数之和及其出现的次数。
2.遍历并构建哈希表:
遍历nums1和nums2的所有组合,计算每对数的和(ikey)。
检查哈希表中是否已经存在这个键(两数之和)。
如果不存在,则创建一个新的哈希表项,键为两数之和,值为1(表示这个和第一次出现)。
如果已经存在,则增加该键对应的值(表示这个和又出现了一次)。
3.利用哈希表查找:
遍历nums3和nums4的所有组合,计算每对数的和的相反数(-ikey)。
在哈希表中查找这个相反数。
如果找到了,则将哈希表中该键对应的值累加到结果变量中,因为这个值表示在nums1和nums2中有多少对数的和与当前nums3和nums4中的数对的和互为相反数。
4.返回结果:
遍历完成后,结果变量中存储的就是所有满足条件的四元组的个数,返回这个结果。
代码实现
struct hashTable {
int key; // 哈希表项的键,用于存储nums1[i] + nums2[j]的和
int val; // 哈希表项的值,用于存储键出现的次数
UT_hash_handle hh; // uthash库提供的数据结构,用于处理哈希表的相关操作
};
// 计算四数之和为零的元组个数
int fourSumCount(int* nums1, int nums1Size, int* nums2, int nums2Size,
int* nums3, int nums3Size, int* nums4, int nums4Size) {
struct hashTable* hashtable = NULL; // 初始化哈希表为空
// 遍历nums1和nums2的所有组合,计算两数之和,并更新哈希表
for (int i = 0; i < nums1Size; i++) {
for (int j = 0; j < nums2Size; j++) {
int ikey = nums1[i] + nums2[j]; // 计算两数之和
struct hashTable* tmp;
HASH_FIND_INT(hashtable, &ikey, tmp); // 在哈希表中查找键ikey
if (tmp == NULL) {
// 如果没找到,则新建一个哈希表项
struct hashTable* tmp = malloc(sizeof(struct hashTable));
tmp->key = ikey;
tmp->val = 1; // 初始值为1,表示找到了一对数的和为ikey
HASH_ADD_INT(hashtable, key, tmp); // 将新项添加到哈希表中
} else {
// 如果找到了,则增加该键对应的值,表示又找到了一对数的和为ikey
tmp->val++;
}
}
}
int ans = 0; // 初始化结果变量为0
// 遍历nums3和nums4的所有组合,计算两数之和的相反数,并在哈希表中查找该相反数
for (int i = 0; i < nums3Size; i++) {
for (int j = 0; j < nums4Size; j++) {
int ikey = -nums3[i] - nums4[j]; // 计算两数之和的相反数
struct hashTable* tmp;
HASH_FIND_INT(hashtable, &ikey, tmp); // 在哈希表中查找该相反数
if (tmp != NULL) {
// 如果找到了,则将该键对应的值累加到结果变量中
// 因为对于nums3和nums4中的每一对数的和,如果哈希表中存在相反数,
// 则说明在nums1和nums2中存在另一对数的和与该相反数相等,从而四数之和为零
ans += tmp->val;
}
}
}
return ans;//返回结果
}
4. 寻找两个正序数组的中位数
题目描述
给定两个大小分别为 m
和 n
的正序(从小到大)数组 nums1
和 nums2
。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n))
。
示例 1:
输入:nums1 = [1,3], nums2 = [2] 输出:2.00000 解释:合并数组 = [1,2,3] ,中位数 2
示例 2:
输入:nums1 = [1,2], nums2 = [3,4] 输出:2.50000 解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
提示:
nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106
解题思路
中位数是将一组数据从小到大(或从大到小)重新排列后,最中间的那个数(如果数据数量是奇数)或者最中间两个数的平均值(如果数据数量是偶数)。
由于题目中的数组已经是排序好的,可以利用这个性质,使用双指针法。其基本思路是,同时遍历两个数组,每次从两个数组的头部取较小的那个元素放入新数组,直到遍历完两个数组或者新数组达到所需长度。
具体步骤如下:
初始化两个指针i和j,分别指向两个数组的起始位置。
初始化一个临时数组用于存储合并后的元素,以及一个索引index用于记录当前存储的位置。
进入循环,比较两个指针所指向的元素大小,将较小的元素放入临时数组,并移动相应指针和索引。
当一个数组遍历完时,将另一个数组剩余的元素依次放入临时数组。
根据临时数组的长度,计算中位数。如果长度是奇数,则中位数是中间的元素;如果长度是偶数,则中位数是中间两个元素的平均值。
需要注意的是,由于题目中要求返回的是double类型,所以在计算中位数时,如果数组长度是偶数,我们需要确保进行浮点数除法,即将两个数相加后再除以2.0,而不是进行整数除法。
代码实现
double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2,int nums2Size) {
int i = 0, j = 0; // 初始化两个数组的索引
int arrSize = nums1Size + nums2Size; // 合并后数组的大小
int* arr = (int*)malloc(arrSize * sizeof(int)); // 动态分配合并后数组的内存
int index = 0; // 合并后数组的索引
// 合并两个数组,将较小的数按顺序放入arr中
while (i < nums1Size && j < nums2Size) {
if (nums1[i] < nums2[j]) {
arr[index++] = nums1[i++];
} else {
arr[index++] = nums2[j++];
}
}
// 如果nums1还有剩余元素,将其添加到arr中
while (i < nums1Size) {
arr[index++] = nums1[i++];
}
// 如果nums2还有剩余元素,将其添加到arr中
while (j < nums2Size) {
arr[index++] = nums2[j++];
}
double mid; // 中位数
// 根据合并后数组的大小计算中位数
if (arrSize % 2 == 0) {
// 如果数组长度是偶数,则中位数是中间两个数的平均值
mid = (arr[arrSize / 2 - 1] + arr[arrSize / 2]) / 2.0;
} else {
// 如果数组长度是奇数,则中位数是中间的数
mid = arr[arrSize / 2];
}
// 返回中位数
return mid;
}