LEETCODE-1.两数之和
题目-两数之和
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum
方法一 暴力枚举
思路非常简单,通过两层循环检验每一对数字之和是否等于目标值。
Note: The returned array must be malloced, assume caller calls free().
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
for (int i = 0; i < numsSize - 1; i++)
{
for (int j = i + 1; j < numsSize; j++)
{
if (nums[i] + nums[j] == target)
{
result[0] = i;
result[1] = j;
*returnSize = 2;
return result;
}
}
}
return 0;
}
方法二 hash查找
方法一的复杂度在于,要想得知外层循环当前所在的数字是否为满足和要求的数字,需要将其后的所有数字都查询一遍,复杂度为O(n^2)。引入哈希表的思路是可以直接找到需要的数字是否在数组中,可以将复杂度降至O(n)。
哈希表的构建:
- 将hash[MAX_SIZE]的每一项初始化为-1
- 对nums数组进行遍历,假设当前对象为nums[i]
- 查看hash[nums[i]],如果该项的值为-1,就将其替换为i
例:
nums数组:[2 , 4 , 6 , 7]
nums下标: 0 1 2 3
hash表:[ -1,-1,0, -1, 1,-1, 2, 3,…]
hash下标:0 1 2 3 4 5 6 7
由此得到的hash表,可以作为第二个和因子的查询表。这样在外层循环当前指向nums[i]时,只需要查找hash[target - nums[i]]的值,如果为-1说明target - nums[i]在数组中不存在,如果为自然数则为target - nums[i]在数组中的位置。
另外需要注意的是,可能会出现负数,对于负数的操作则补充到hash表的队尾。
int *twoSum(int *nums, int numsSize, int target, int *returnSize)
{
int i, hash[2048], *res = (int *)malloc(sizeof(int) * 2);
memset(hash, -1, sizeof(hash));
for (i = 0; i < numsSize; i++)
{
if (hash[(target - nums[i] + 2048) % 2048] != -1)
{
res[0] = hash[(target - nums[i] + 2048) % 2048];
res[1] = i;
*returnSize = 2;
return res;
}
hash[(nums[i] + 2048) % 2048] = i;
}
free(hash);
*returnSize = 0;
return res;
}
该算法要求hash表的大小需要足够大,不能发生正数区和负数区的碰撞。
通过在hash表中增加一项标记,标明每个项目入表时是正值还是负值可以解决一部分问题。
参考
https://leetcode-cn.com/problems/two-sum/solution/cyu-yan-ji-yu-shu-zu-de-san-lie-15xing-dai-ma-8ms-/