leetcode T1 两数之和详解
Posted xiaoxxmu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode T1 两数之和详解相关的知识,希望对你有一定的参考价值。
两数之和
题目描述
给定一个整数数组 nums?和一个目标值 target,请你在该数组中找出和为目标值的那?两个?整数,并返回他们的数组下标。你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
示例
给定 nums = [2, 7, 11, 15], target = 9,因为 nums[0] + nums[1] = 2 + 7 = 9,所以返回 [0, 1]
详细题解
暴力枚举
暴力法的思路很简单:遍历数组nums的每一个元素nums[i],在[i+1, ..., numsSize-1]中遍历查找是否存在j,使得target = nums[i] + nums[j]。
int *twoSum(int *nums, int numsSize, int target, int *returnSize)
{
int *retArr = NULL;
int i, j;
for (i = 0; i < numsSize - 1; i++) {
for (j = i + 1; j < numsSize; j++) {
if (nums[i] + nums[j] == target) {
retArr = malloc(sizeof(int) * 2);
assert(retArr != NULL);
retArr[0] = i;
retArr[1] = j;
*returnSize = 2;
return retArr;
}
}
}
*returnSize = 0;
return NULL;
}
排序+双指针
如果在有序表中查找两数之和等于target,可以用双指针,从两头向中间枚举,时间复杂度O(n)
有了这个想法,可以先将nums数组排序,然后再用双指针枚举,只不过排序的时候要注意,需要带上原始的数组下标进行排序
void qsortWithIndex(int *nums, int *indexArr, int left, int right)
{
int i, j, pivot, pIndex;
if (left >= right) {
return;
}
i = left;
j = right;
pivot = nums[left];
pIndex = indexArr[left];
while (i < j) {
while (i < j && pivot <= nums[j]) {
j--;
}
nums[i] = nums[j];
indexArr[i] = indexArr[j];
while (i < j && pivot >= nums[i]) {
i++;
}
nums[j] = nums[i];
indexArr[j] = indexArr[i];
}
nums[i] = pivot;
indexArr[i] = pIndex;
qsortWithIndex(nums, indexArr, left, i - 1);
qsortWithIndex(nums, indexArr, i + 1, right);
}
int *twoSum(int *nums, int numsSize, int target, int *returnSize)
{
int *indexArr = NULL;
int *retArr = NULL;
int i, j;
indexArr = malloc(sizeof(int) * numsSize);
assert(indexArr != NULL);
for (i = 0; i < numsSize; i++) {
indexArr[i] = i;
}
qsortWithIndex(nums, indexArr, 0, numsSize - 1);
i = 0;
j = numsSize - 1;
while (i < j) {
if (nums[i] + nums[j] == target) {
retArr = malloc(sizeof(int) * 2);
assert(retArr != NULL);
*returnSize = 2;
retArr[0] = indexArr[i];
retArr[1] = indexArr[j];
free(indexArr);
return retArr;
} else if (nums[i] + nums[j] > target) {
j--;
} else {
i++;
}
}
free(indexArr);
*returnSize = 0;
return NULL;
}
哈希
使用一个哈希表存放已经查询过的元素值和对应的下标
遍历数组nums中的每一个元素nums[i],在哈希表中查询是否存在值为target-nums[i]的元素
如果存在,则找到了相应的解,如果不存在,则将(nums[i],i)插入到哈希表中
#define MAX_NUMS_SIZE 1000001
typedef struct HashNode {
int index;
int value;
} HashNode;
HashNode node[MAX_NUMS_SIZE];
void hashPut(HashNode **hashTable, HashNode *hashNode)
{
int index;
if (hashNode->value >= 0) {
index = hashNode->value % MAX_NUMS_SIZE;
} else {
index = -1 * hashNode->value % MAX_NUMS_SIZE;
}
while (hashTable[index]) {
index = (index + 1) % MAX_NUMS_SIZE;
}
hashTable[index] = hashNode;
}
HashNode *hashGet(HashNode **hashTable, int value)
{
int index;
if (value >= 0) {
index = value % MAX_NUMS_SIZE;
} else {
index = -1 * value % MAX_NUMS_SIZE;
}
while (hashTable[index]) {
if (hashTable[index]->value != value) {
index = (index + 1) % MAX_NUMS_SIZE;
} else {
return hashTable[index];
}
}
return NULL;
}
int *twoSum(int *nums, int numsSize, int target, int *returnSize)
{
HashNode *hashTable[MAX_NUMS_SIZE] = {NULL};
HashNode *hashNode = NULL;
int *retArr = NULL;
int i;
if (!numsSize || !nums) {
*returnSize = 0;
return NULL;
}
for (i = 0; i < numsSize; i++) {
hashNode = hashGet(hashTable, target - nums[i]);
if (hashNode) {
retArr = malloc(sizeof(int) * 2);
assert(retArr != NULL);
*returnSize = 2;
retArr[0] = hashNode->index;
retArr[1] = i;
return retArr;
}
node[i].index = i;
node[i].value = nums[i];
hashPut(hashTable, &node[i]);
}
*returnSize = 0;
return NULL;
}
方法 | 时间复杂度 | 空间复杂度 | 结果 | 时间 | 内存 |
---|---|---|---|---|---|
方法 | 时间复杂度 | 空间复杂度 | 结果 | 时间 | 内存 |
暴力枚举 | O(n2) | O(1) | 通过 | 180ms | 7.6M |
排序+双指针 | O(nlog2n) | O(n) | 通过 | 96ms | 8.4M |
哈希 | O(n) | O(n) | 通过 | 20ms | 15.3M |
?
?
?
?
?
?
以上是关于leetcode T1 两数之和详解的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode167. 两数之和 II - 输入有序数组(C++)