0001 两数之和
简单 哈希
算法思路
简单而言,我们需要在一个整数数组中找到特定的两个数 a b,使得 a b 之和为目标 target。
最直接的解法显然遍历每个整数对并计算两者之和,当结果满足条件时结束并返回。显然,暴力计算的时间复杂度为 \(O(n^2)\)。
初见此题,我在排除暴力计算后,第一反应是先将数组排序,然后在大概 target/2 处创建两个指针分别向两侧遍历,直到找到满足条件的整数对。
这样寻找整数对的时间复杂度简化为\(O(n)\)。
显然,上述思考引入新的问题:排序。对于整数数组排序,不可避免的时间复杂度来到了\(O(nlogn)\)。
因此,思路逐渐清晰:我们需要在不排序的前提下,对于整数数组中的一个数 a,快速(\(O(1)\)复杂度内)确定数组中是否存在一个值为 target-a 的数。
从而得出方法:哈希。最终时间复杂度为 \(O(n)\),空间复杂度为 \(O(n)\)。
代码实现
two-sum.c
struct hashTable {
int key;
int val;
UT_hash_handle hh;
};
struct hashTable* hashtable;
struct hashTable* find(int ikey) {
struct hashTable* tmp;
HASH_FIND_INT(hashtable, &ikey, tmp);
return tmp;
}
void insert(int ikey, int ival) {
struct hashTable* it = find(ikey);
if (it == NULL) {
struct hashTable* tmp = malloc(sizeof(struct hashTable));
tmp->key = ikey, tmp->val = ival;
HASH_ADD_INT(hashtable, key, tmp);
} else {
it->val = ival;
}
}
int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
hashtable = NULL;
for (int i = 0; i < numsSize; i++) {
struct hashTable* it = find(target - nums[i]);
if (it != NULL) {
int* ret = malloc(sizeof(int) * 2);
ret[0] = it->val, ret[1] = i;
*returnSize = 2;
return ret;
}
insert(nums[i], i);
}
*returnSize = 0;
return NULL;
}
/*
作者:力扣官方题解
链接:https://leetcode.cn/problems/two-sum/solutions/434597/liang-shu-zhi-he-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*/
知识补充
上述代码使用了 uthash 库(一个用 C 宏实现的哈希表)。
对于结构体 hashTable,其中的 UT_hash_handle hh 是 uthash 库要求必须添加的成员。UT_hash_handle 一个内部结构体类型,它包含了用于维护哈希表的前驱、后继、哈希值、桶索引等指针信息。这个成员使得该结构体可以被 uthash 的宏管理。
HASH_FIND_INT(hashtable, &ikey, tmp);:这是一个 uthash 提供的宏,用于在哈希表中查找键为 ikey 的元素。
HASH_ADD_INT(hashtable, key, tmp);:将新节点 tmp 添加到哈希表中。