標籤:
題目要求:
Download the text file here. (Right click and save link as).
The goal of this problem is to implement a variant of the 2-SUM algorithm (covered in the Week 6 lecture on hash table applications).
The file contains 1 million integers, both positive and negative (there might be some repetitions!).This is your array of integers, with the ith row of the file specifying the ith entry of the array.
Your task is to compute the number of target values t in the interval [-10000,10000] (inclusive) such that there are distinct numbers x,y in the input file that satisfy x+y=t. (NOTE: ensuring distinctness requires a one-line addition to the algorithm from lecture.)
Write your numeric answer (an integer between 0 and 20001) in the space provided.
OPTIONAL CHALLENGE: If this problem is too easy for you, try implementing your own hash table for it. For example, you could compare performance under the chaining and open addressing approaches to resolving collisions.
大致意思是說,有一百萬個數字(正負都有,且可能重複)。目標是要尋找到唯一存在的數對(x,y),使得x+y屬於[-10000, 10000]的範圍中,最後輸出這些數對的個數。
檔案中的資料差不多是這樣子的:
...-92205919974-65150999169-9624798614470191728682-59670982771-10202710755-72167080349-1922161398580341418823-79433686277873517134166084932343408017526104402824795984203784346-281203864745906443137639436465566-89458683408-64200776240-42582579303-6265688853555650079602629541755483371363921770259349593-97472959477418901481394421621297626864335558...
解題思路:
起初採用了最暴力的方法,直接把這些數字塞進一個hash table中,然後遍曆著去查詢(這個方法很不好,所以就不詳述了),結果運行了很久都沒有跑出結果,遂直接放棄這種方法。
這裡的問題在於如下兩點:
- 資料量多達一百萬條;
- 大部分數對相加的和,遠超要求的範圍之外。
因此針對問題的實際情況進行了些許最佳化,大致思路如下:
- 假設X為檔案中的一個數字;
- 建立一個hash table,它的鍵為X/10000,值為由對應X組成的set。這樣就相當於把輸入的資料以10000作為一個範圍對其進行劃分,最後劃分成若干組資料,之所以要將10000作為劃分的範圍,是因為題目中要求數對的和在[-10000, 10000]的範圍中,這樣對於我們這裡的hash table,給定一個key1,我們就能知道可能有哪些key2對應集合中的數與key1集合中的數相加,是可以在要求的範圍中的;
- 具體而言,對於一個key1,可取的key2有:{-key1-2, -key1-1, -key1}這三個。注意因為之前的X/10000是整除,其結果為向下取整,如 -14000 / 10000 = -2;
- 在已知了key1與key2之後,對其集合中的數進行迴圈遍曆,如果相加的和在題目要求的範圍內,那麼就將計數器加一。
利用上述思路,可以避免大量的不必要的運算,另外我們還可以對其進行進一步的最佳化:
- 對key1進行遍曆的時候,只取key1小於或等於零的值,這樣可以進一步減少重複計算;
- 建立一個儲存結果的set,如果找到了滿足要求的數對(x, y),那麼就置result[x+y] = True,最後輸出result的大小。
代碼實現:
有了上述的思路,利用Python對其進行了實現,代碼如下:
result = {}dic = {}input_file = open("algo1-programming_prob-2sum.txt")# 讀入資料for line in input_file: num = long(line) key = num/10000 if key not in dic: dic[key] = {} # 這裡記錄資料出現的次數,用來判斷該數是否是唯一的 if num in dic[key]: dic[key][num] += 1 else: dic[key][num] = 1for key1 in dic: # 忽略key1 > 0的情況,減少不必要的重複計算 if key1 > 0: continue # 根據給定的key1,可以推測出key2可取的值 for key2 in range(-key1-2, -key1 + 1): if key2 in dic: # 對key1和key2對應集合中的數進行遍曆 for value2 in dic[key2]: for value1 in dic[key1]: # 判斷這兩個數是否是唯一的 if dic[key1][value1] != 1 or dic[key2][value2] != 1: continue sum_tmp = value1+value2 # 判斷兩數之和是否在題目要求的範圍內 if abs(sum_tmp) <= 10000 and sum_tmp not in result: result[sum] = True# 輸出結果print len(result)
input_file.close()
這段代碼在我的電腦上運行僅需要大約3-4秒的時間就能跑出結果(包含讀取資料的I/O操作的時間),可見該方法有效地避免了大量不必要的計算。
另外,題目中要求找到唯一存在的數對(x, y),但是如果把代碼中判斷唯一性的那個條件判斷去除,得到的結果也是一樣的,這也許和給出的資料有關。
一個"2-SUM"問題