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 两数之和详解的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode1. 两数之和(C++)

LeetCode167. 两数之和 II - 输入有序数组(C++)

Leetcode 1. 两数之和(带图)

LeetCode:两数之和

⭐算法入门⭐《二叉树 - 二叉搜索树》简单01 —— LeetCode 653. 两数之和 IV - 输入 BST

LeetCode 1两数之和