簡體   English   中英

從兩個列表中找到2個數字的最快方法,總和等於x

[英]The fastest way to find 2 numbers from two lists that in sum equal to x

我的代碼:

n = 3
a1 = 0
b1 = 10
a2 = 2
b2 = 2

if b1>n:
    b1=n
if b2>n:
    b2=n

diap1 = [x for x in range(a1, b1+1)]
diap2 = [x for x in range(a2, b2+1)]

def pairs(d1, d2, n):
    res = 0
    same = 0
    sl1 = sorted(d1)
    sl2 = sorted(d2)
    for i in sl1:
        for j in sl2:
            if i+j==n and i!=j:
                res+=1
            elif i+j==n and i==j:
                same+=1
    return(res+same)

result = pairs(diap1, diap2, n)
print(result)

注意: n,a1,b1,a2,b2 可以改變 代碼應該從2個列表中找到2個數字(每個1個),總和等於n。 例如:對(a,b)和(b,a) 不同,但(a,a)和(a,a) 是同一對 因此,我的代碼輸出是正確的,對於上面的代碼是1(1,2),但對於大輸入,它需要太多時間。 如何優化它以更快地工作?

使用set()進行快速查找...

setd2 = set(d2)

不要嘗試所有可能的數字對。 一旦你修復了第一個列表中的數字,比如i,只要看看(ni)是否在第二個集合中。

for i in sl1:
    if (n-i) in setd2:
        # found match
    else:
        # no match in setd2 for i

通過以下方式,您可以最快地工作並找到總和等於n的兩個數字,並將它們存儲在元組列表中。

s1 = set(list1)
s2 = set(list2)
nums = []
for item in s1:
    if n-item in s2:
       nums.append((item, n-item))

接受的答案很容易理解和實現,但我只需要分享這種方法。 你可以看到你的問題是一樣的,因為這一個
這個答案特別有趣,因為插入集合不需要額外的空間。 我在答案中包含了算法。

如果對數組進行排序,則可以在線性時間和常量存儲中進行排序。

  • 從兩個指針開始,一個指向A的最小元素,另一個指向B的最大元素。
  • 計算指向元素的總和。
  • 如果小於k,則將指針增加到A,使其指向下一個最大元素。
  • 如果它大於k,則將指針遞減到B,使其指向下一個最小元素。
  • 如果它恰好是k,你就找到了一對。 移動其中一個指針,繼續尋找下一對。

如果數組最初未排序,那么您可以先對它們進行排序,然后使用上述算法。

感謝您明確定義問題並提供您嘗試優化的代碼示例。

利用您問題中的兩個關鍵定義和您提供的符號,我將優化嘗試限制為使用列表,並添加了隨機更改與n,a1,b1,a2和b2關聯的值的功能。

為了顯示優化結果,我創建了一個模塊,其中包括使用random.randit函數創建各種列表大小和timeit.Timer函數來捕獲原始pair()函數所需的時間量正如我在pairs2()函數中建議的優化。

在pairs2()函數中,您將注意到每個迭代循環都包含一個break語句。 一旦滿足所需的標准,這些就消除了對每個列表的不必要的迭代。 您應該注意,隨着列表大小的增加,pairs2()與pairs()時間會有所改善。

測試模塊代碼:

import random
from timeit import Timer

max_value = 10000
n =  random.randint(1, max_value)
a1 = random.randint(0, max_value)
b1 = random.randint(1, max_value+1)
a2 = random.randint(0, max_value)
b2 = random.randint(1, max_value+1)

if b1>n:
    b1=n
if b2>n:
    b2=n

if a1>=b1:
    a1 = random.randint(0, b1-1)
if a2>=b2:
    a2 = random.randint(0, b2-1)

diap1 = [x for x in range(a1, b1)]
diap2 = [x for x in range(a2, b2)]
print("Length diap1 =", len(diap1))
print("Length diap2 =", len(diap2))

def pairs(d1, d2, n): 
    res = 0 
    same = 0    
    sl1 = sorted(d1)
    sl2 = sorted(d2)
    for i in sl1:
        for j in sl2:
            if i+j==n and i!=j:                 
                res+=1                                          
            elif i+j==n and i==j:
                same+=1
    return(res+same)

def pairs2(d1, d2, n): 
    res = 0 
    same = 0    
    sl1 = sorted(d1)
    sl2 = sorted(d2)
    for i in sl1:
        for j in sl2:
            if i+j==n and i!=j:                 
                res+=1
                break                                      
            elif i+j==n and i==j:
                same+=1
                break
        if res+same>0:
            break
    return(res+same)

if __name__ == "__main__":
    result=0
    timer = Timer("result = pairs(diap1, diap2, n)",
                  "from __main__ import diap1, diap2, n, pairs")
    print("pairs_time = ", timer.timeit(number=1), "result =", result)

    result=0
    timer = Timer("result = pairs2(diap1, diap2, n)",
              "from __main__ import diap1, diap2, n, pairs2")
    print("pairs2_time = ", timer.timeit(number=1), "result =", result)

如果從第一個列表中提取值n,然后在第二個列表中搜索值m以使總和與搜索到的值匹配,則可以創建一些快捷方式。 例如,如果總和較小,則第二個列表中小於或等於m的所有值也不會給出正確的總和。 同樣,如果總和更大。

使用此信息,我將使用以下步驟:

  • 設置兩個堆,一個最小堆,一個最大堆。
  • 查看每個堆的頂部元素:
    • 如果總和與搜索到的值匹配,則表示您已完成。
    • 如果總和超過搜索值,請從最大堆中刪除該值。
    • 如果總和小於搜索值,則從最小堆中刪除該值。
  • 如果任何一個堆為空,則沒有解決方案。

請注意,使用堆是對兩個序列進行分類排序的優化。 但是,如果您經常遇到無匹配的情況,則在算法之前對數字進行排序可能是一種更快的方法。 這樣做的原因是一個好的排序算法將勝過通過堆的隱式排序,而不是通過其漸近復雜性而是通過一些常數因子。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM