1. 程式人生 > >leetcode 第一題:使用雜湊表解決

leetcode 第一題:使用雜湊表解決

題目大意:給定一個整數,試從給定的vector中尋找到兩個成員,使它們的和等於給定的整數。

說明:預設答案具有唯一解,且同一個成員不可以使用兩次。

例子:對於[2,7,11,13],給定整數18,則應當返回成員“7”和“11”在此vector中的位置1和2。

解題思路:

       剛剛看到這道題的時候感覺非常簡單,但隨即腦海中冒出幾個問題:

       1.vector中有重複元素嗎?

       答:這個問題比較重要,因為這關係到演算法的選擇。題目中並沒有說明這一點,但它強調了一個成員不可以使用兩次,也就相當於默認了不會有重複元素。

       2.vector會有負數嗎?

       答:會存在負數。

       明確這兩點之後我就開始尋找解題思路。最“”的方法當前就是從頭開始一個個地求和,再將結果與給定的整數比較:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
    int i,j,number,sum,flag=0;
	vector<int> ans;
	number=nums.size();  //vector中元素的數目
	for(i=0;i<=number-2;i++)
	{
		for(j=i+1;j<=number-1;j++)
		{
			sum=nums[i]+nums[j];
			if(sum==target)
				{
					flag=1;
					break;
			    }
		}
		if(flag)
		{
			break;
		}
	}
	ans.push_back(i);
	ans.push_back(j);
	return ans;
    }
};
 雖然AC了,但耗時太長(這是顯然的,因為其演算法複雜度是O(N^2))。之後我又朝幾個方向尋找了答案,包括先排序再查詢比較、二分法比較。但都沒有比較明確的思路。

        在參考了Disscussion中的答案後,我發現用Hash Table來解決這道問題非常快。因為比較的物件是vector中兩個成員之和,所以不妨建立一個以vector元素為鍵,對應下標為值的map。隨後將給定的整數與vector中元素相減,若map中存在成員,其鍵等於相減得到的餘數,則說明找到了符合要求的兩個成員。話不多說,程式碼如下:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
    map<int,int> hash;  //建立雜湊表
	vector<int> ans;
	int i,complement;
	for(i=0;i<nums.size();i++)
	{
		complement=target-nums[i];
		if(hash.find(complement)!=hash.end())  //如果找到的話,則將元素插入結果中並返回
		{
			ans.push_back(hash[complement]);
			ans.push_back(i);
			return ans;
		}
		hash[nums[i]]=i;    
	}
	return ans;
    }
};
這裡做了一點小的優化。雜湊表並不是一開始就用vector中的元素將其建立完畢,而是在查詢的過程中逐步建立的,邊查詢邊建立雜湊表,從而進一步降低了演算法複雜度。最後的結果也表明,對於相同的case,執行時間從之前的109ms降低到了9ms,符合我的預期。

       這道題充分說明了查表的速度是遠遠快於迴圈的。雜湊表作為一種常見的資料結構,值得我們注意。另外,最後一個優化過程的泛用性比較強,很多時候進行陣列內元素比較,可以嘗試“從小到大”,逐步新增的思路。這在我之前刷POJ與HDOJ的題目時遇到過,只是沒有引起重視。