LeetCode 热题 100 - 第1题:两数之和
- 原题
- 题目理解
- 普通的解题思路---遍历查找
- 进阶的解题思路---哈希查找
原题
给定一个整数数组 nums和一个整数目标值target,请你在该数组中找出 和为目标值 target的那两个整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出: [0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1]
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]
提示:
2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
只会存在一个有效答案
题目理解
这个题目有几个关键点:
- 计算仅限于整数
- 只会存在一个有效答案------找到一组答案就可以退出程序
- 数组里同一个元素在答案里不能重复出现------数组里的元素不能自己和自己相加
- 限定了nums[i], nums.length, target的值的范围------32位整形数就不会溢出
普通的解题思路—遍历查找
穷举法,为每个元素num[i]去遍历数组里除自己外的所有元素查找是否存在 num[j] = target−num[i]找到则返回。这个算法的时间复杂度是O(N2)。
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
int i;
int j;
for(i = 0; i < numsSize; i++)
{
for(j = i + 1; j < numsSize; j++)
{
if (nums[i] + nums[j] == target)
{
int* result = malloc(sizeof(int) * 2);
result[0] = i;
result[1] = j;
*returnSize = 2;
return result;
}
}
}
*returnSize = 0;
return NULL;
}
结果:
结果很一般,只是达到了能用的层次。
进阶的解题思路—哈希查找
leetcode是用来考算法的,所以我们要明白,这里需要的进阶的解题思路不是在原有的代码做代码级的优化,而是要求做算法级的优化。我们正常的解题思路下:针对数组里的N个数字,给每一个数字去便历查找所有N-1个数字看N-1里哪个数字等于我们要查找的数,所以总体上来讲,在最差情况下每个数都要和除它自己之外的所有数据做过比较,所以要做N*N-1次查找,实际上因为我们只比较当前数和排在它后面的数,因为排在它前面的数,已经在之前的数字和其它数比较时比较过了,不需要重复比较,所以是N*(N-1)/2次,总体上来说时间复杂度是O(N2)。
这里我们需要一个新的算法,目标是将时间复杂度降低到O(N)。学过数据结构的我们都知道哈希表用于查找时,相比于遍历法,可以将查找N个数字的次数从N降低到1(不考虑散列计算和假设不会产生不需要解决散列冲突需要的额外时间的前提下,哈希表的查找是直接命中需要查找的数或者直接返回找不到的),所以自然而然就可以想到用哈希表来解决这个问题,思路也很简洁:
遍历N个数字,当遍历到第n个数字(假设第n个数字的值为n_value)时,就去查找哈希表中有没有等于target-n_value的数,如果有,则返回n和哈希表中的数字在数组中的下标),如果没有,则将当前数的值做为key, 下标做为value存入哈希表。
那么这时需要比较的次数就降低为N*1次,所以总体上来说时间复杂度就降低到是O(N)了。
**
* Note: The returned array must be malloced, assume caller calls free().
*/
struct hashTable
{
int key;
int value;
UT_hash_handle hh;
};
struct hashTable* hashtable;
struct hashTable* find_node(int key)
{
struct hashTable* node;
HASH_FIND_INT(hashtable, &key, node);
return node;
}
void insert_node(int key, int value)
{
struct hashTable* node = malloc(sizeof(struct hashTable));
node->key = key, node->value = value;
HASH_ADD_INT(hashtable, key, node);
}
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
hashtable = NULL;
for (int i = 0; i < numsSize; i++)
{
struct hashTable* node = find_node(target - nums[i]);
if (node != NULL)
{
int* result = malloc(sizeof(int) * 2);
result[0] = node->value;
result[1] = i;
*returnSize = 2;
return result;
}
else
{
insert_node(nums[i], i);
}
}
*returnSize = 0;
return NULL;
}
结果:
以空间换时间,达到了速度极快的层次。