目錄
前言:
本題的採用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;
}
解題思路:
- 題目中表明,傳入的數組中最多有一個有效答案,所以對數組進行遍歷即可。
- 因爲找兩數之和,所以從第一個元素開始遍歷至最後一個元素,最多的遍歷次數爲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;
}
解題思路:
- 本題可以換一個角度考慮:已知target和nums[i],尋找兩者之差的數值是否在nums中,並且獲得其座標值
- 問題就轉換爲數據搜索查詢
- 哈希表(散列表)既有數組快速查詢的優點,又有鏈表快速插入、刪除的優點。在數據存儲查詢的領域中十分常用
- 借鑑哈希表和本題的思路,將已知元素nums[n]作爲鍵(本題中所有的nums必不重複)通過哈希算法填充到指定的哈希表中,可以實現時間爲O(1)的查詢速度
- 用於本題的哈希算法 #define(key, size) ((key%size) + 1) // 0作爲判斷非空,所以數值整體+1
- 實現哈希的插入、尋找算法
- 循環調用即可
解題結果:
總結與思考:
通過上述兩種解題思路的比較可以發現,暴力解題思路簡單,並且實現起來很方便,但是在時間上面卻輸的特別慘。採用哈希表的數據結構與算法,在查找和插入元素過程中具有顯著優勢,因此在解題時間上面有“飛”的感覺。
通過本題,get到一個新技能,就是哈希表的運用。
來源:
https://leetcode-cn.com/problems/two-sum/
參考:
- 關於哈希表的思路參考學習了力口中的評論
- 哈希表原理說明:https://blog.csdn.net/yyyljw/article/details/80903391