欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Task1——两数之和

程序员文章站 2022-04-08 12:59:31
...

目录

前言:

题目:

示例:

暴力解题过程:

解题思路:

解题结果:

哈希解题过程:

解题思路:

解题结果:

总结与思考:

来源:

参考:


前言:

本题的采用C语言解决问题,并使用了两种解题思路。

题目:

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

暴力解题过程:

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
    int* idx = (int*)malloc(sizeof(int)*2);
    for(int i=0; i<numsSize-1; i++)
    {
        for(int j=i+1; j<numsSize; j++)
        {
            if(nums[i]+nums[j] == target)
            {
                idx[0] = i;
                idx[1] = j;
                returnSize[0] = 2;
                return idx;
            }
        }
    }
    returnSize = 0;
    return 0;
}

解题思路:

  1. 题目中表明,传入的数组中最多有一个有效答案,所以对数组进行遍历即可。
  2. 因为找两数之和,所以从第一个元素开始遍历至最后一个元素,最多的遍历次数为n!(其中n为数组长度)

解题结果:

Task1——两数之和

哈希解题过程:


#include <math.h> 
#define hash_fn(key, size) (abs(key%size)+1) // 使用0判断hash是否填充
#define prob_fn(key, size) (abs(key%size)+1) // 使用0判断hash是否填充

typedef struct _HashTable_t
{
    int hash; // 用于判断当前哈希数组元素是否有填充,若为0即为无填充
    int key;  // 键 -- 唯一性
    int val;  // 值 -- 存放被查询元素
}HashTable_t;

void HashInsert(HashTable_t* t, int tSize, int key, int val)
{
    int hash = hash_fn(key, tSize);
    int idx = hash;
    // 寻找哈希表中为0的数组元素
    while (t[idx].hash)
    {
	idx = prob_fn(idx, tSize);
    }
    // 将目标哈希数组填充
    t[idx] = (HashTable_t){ hash, key, val };
}

#include <stdbool.h>
bool HashFind(HashTable_t* t, int size, int key, int* val) 
{
    // 获取指定键的哈希值
    int hash = hash_fn(key, size);
    int idx = hash;
    // 寻找hash非0,且键相等的元素
    while (t[idx].hash && t[idx].key != key)
    {
	idx = prob_fn(idx, size);
    }
    val[0] = t[idx].val;
    // 返回hash值是否相同
    return t[idx].hash == hash;
}

#include <stdlib.h>
int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
    int* p = (int*)malloc(sizeof(int) * 2);
    // 由于传进来的参数中包含数组的长度
    // 所以分配足够的哈希空间
    int tSize = numsSize * 2; 
    HashTable_t *t = calloc(tSize+1, sizeof(HashTable_t));
    for (int i = 0; i < numsSize; i++)
    {
        // 寻找数值为 (target-nums[i]) 的元素的索引
	if (HashFind(t, tSize, target - nums[i], &p[1]))
	{
            // 找到后,将索引存储于缓存 p 中
	    p[0] = i;
	    *returnSize = 2;
            free(t);
	    return p;
	}
	else
	{
            // 否则将键值对 -- nums[i]:i 存放于哈希表中
	    HashInsert(t, tSize, nums[i], i);
	}
    }
    *returnSize = 0;
    free(p);
    free(t);
    return 0;
}

解题思路:

  1. 本题可以换一个角度考虑:已知target和nums[i],寻找两者之差的数值是否在nums中,并且获得其坐标值
  2. 问题就转换为数据搜索查询
  3. 哈希表(散列表)既有数组快速查询的优点,又有链表快速插入、删除的优点。在数据存储查询的领域中十分常用
  4. 借鉴哈希表和本题的思路,将已知元素nums[n]作为键(本题中所有的nums必不重复)通过哈希算法填充到指定的哈希表中,可以实现时间为O(1)的查询速度
  5. 用于本题的哈希算法 #define(key, size) ((key%size) + 1) // 0作为判断非空,所以数值整体+1
  6. 实现哈希的插入、寻找算法
  7. 循环调用即可

解题结果:

Task1——两数之和

总结与思考:

通过上述两种解题思路的比较可以发现,暴力解题思路简单,并且实现起来很方便,但是在时间上面却输的特别惨。采用哈希表的数据结构与算法,在查找和插入元素过程中具有显著优势,因此在解题时间上面有“飞”的感觉。

通过本题,get到一个新技能,就是哈希表的运用。

来源:

https://leetcode-cn.com/problems/two-sum/

参考:

相关标签: 算法训练