每日练习——leetcode454和4

目录

​​​​454. 四数相加 II

题目描述

解题思路

代码实现

4. 寻找两个正序数组的中位数

题目描述

解题思路

代码实现



题目描述

给你四个整数数组 nums1nums2nums3 和 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;
}

  • 25
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值