Task1——兩數之和

目錄

前言:

題目:

示例:

暴力解題過程:

解題思路:

解題結果:

哈希解題過程:

解題思路:

解題結果:

總結與思考:

來源:

參考:


前言:

本題的採用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爲數組長度)

解題結果:

哈希解題過程:


#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. 循環調用即可

解題結果:

總結與思考:

通過上述兩種解題思路的比較可以發現,暴力解題思路簡單,並且實現起來很方便,但是在時間上面卻輸的特別慘。採用哈希表的數據結構與算法,在查找和插入元素過程中具有顯著優勢,因此在解題時間上面有“飛”的感覺。

通過本題,get到一個新技能,就是哈希表的運用。

來源:

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

參考:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章