簡體   English   中英

在列表中查找因子的最有效方法是什么?

[英]What's the most efficient way to find factors in a list?

我想做什么:

我需要創建一個函數,給定一個正整數列表(可能有重復的整數),計算所有三元組(在列表中),其中第三個數字是第二個的倍數,第二個是第一個的倍數:

(相同的數字不能在一個三元組中使用兩次,但可以被所有其他三元組使用)

例如, [3, 6, 18]是1,因為18均勻分為6 ,均勻分為3

所以給出[1, 2, 3, 4, 5, 6]它應該找到:

[1, 2, 4] [1, 2, 6] [1, 3, 6]

並返回3 (找到的三元組數)

我嘗試過的:

我做了一些有效的功能,但效率不高。 是否有一些我不知道的數學概念可以幫助我更快地找到這些三元組? 具有更好功能的模塊? 我不知道該搜索什么...

def foo(q):
    l = sorted(q)
    ln = range(len(l))
    for x in ln:
        if len(l[x:]) > 1:
            for y in ln[x + 1:]:
                if (len(l[y:]) > 0) and (l[y] % l[x] == 0):
                    for z in ln[y + 1:]:
                        if l[z] % l[y] == 0:
                            ans += 1
    return ans

這個更快一點:

def bar(q):
    l = sorted(q)
    ans = 0
    for x2, x in enumerate(l):
        pool = l[x2 + 1:]
        if len(pool) > 1:
            for y2, y in enumerate(pool):
                pool2 = pool[y2 + 1:]
                if pool2 and (y % x == 0):
                    for z in pool2:
                        if z % y == 0:
                            ans += 1
    return ans

這是我從你們所有人那里得到的幫助,但我必須做錯事,因為它得到了錯誤的答案(盡管它真的很快):

def function4(numbers):
    ans = 0
    num_dict = {}
    index = 0
    for x in numbers:
        index += 1
        num_dict[x] = [y for y in numbers[index:] if y % x == 0]

    for x in numbers:
        for y in num_dict[x]:
            for z in num_dict[y]:
                print(x, y, z)
                ans += 1

    return ans

39889而不是40888 ) - 哦,我不小心將索引var開始為1而不是0.它現在有效。

最終編輯

通過重新評估我需要它做什么,我找到了找到三元組數量的最佳方法。 這種方法實際上並沒有找到三元組,它只計算它們。

def foo(l):
    llen = len(l)
    total = 0
    cache = {}
    for i in range(llen):
        cache[i] = 0
    for x in range(llen):
        for y in range(x + 1, llen):
            if l[y] % l[x] == 0:
                cache[y] += 1
                total += cache[x]
    return total

這里有一個函數版本可以解釋思考過程(雖然因為垃圾郵件打印而對大型列表不利):

def bar(l):
    list_length = len(l)
    total_triples = 0
    cache = {}
    for i in range(list_length):
        cache[i] = 0
    for x in range(list_length):
        print("\n\nfor index[{}]: {}".format(x, l[x]))
        for y in range(x + 1, list_length):
            print("\n\ttry index[{}]: {}".format(y, l[y]))
            if l[y] % l[x] == 0:
                print("\n\t\t{} can be evenly diveded by {}".format(l[y], l[x]))
                cache[y] += 1
                total_triples += cache[x]
                print("\t\tcache[{0}] is now {1}".format(y, cache[y]))
                print("\t\tcount is now {}".format(total_triples))
                print("\t\t(+{} from cache[{}])".format(cache[x], x))
            else:
                print("\n\t\tfalse")
    print("\ntotal number of triples:", total_triples)

現在你的算法有O(N ^ 3)運行時間,這意味着每次你加倍初始列表的長度時,運行時間會增加8倍。

在最壞的情況下,你無法改善這一點。 例如,如果你的數字都是2的連續冪,意味着每個數字除以每個數字都比它更重要,那么每三個數字都是一個有效的解決方案,所以打印出來的所有解決方案都會像你現在在做什么

如果你有一個較低的“密度”數字來划分其他數字,你可以做的一件事就是搜索成對的數字而不是三元組。 這將花費時間僅為O(N ^ 2),這意味着當您將輸入列表的長度加倍時,運行時間會增加4倍。 一旦你有一對數字列表,你可以用它來建立一個三元組列表。

# For simplicity, I assume that a number can't occur more than once in the list.
# You will need to tweak this algorithm to be able to deal with duplicates.

# this dictionary will map each number `n` to the list of other numbers
# that appear on the list that are multiples of `n`.
multiples = {}
for n in numbers:
   multiples[n] = []

# Going through each combination takes time O(N^2)
for x in numbers:
   for y in numbers:
     if x != y and y % x == 0:
         multiples[x].append(y)

# The speed on this last step will depend on how many numbers
# are multiples of other numbers. In the worst case this will
# be just as slow as your current algoritm. In the fastest case
# (when no numbers divide other numbers) then it will be just a
# O(N) scan for the outermost loop.
for x in numbers:
    for y in multiples[x]:
        for z in multiples[y]:
            print(x,y,z)

可能有更快的算法,也利用除法的代數屬性,但在你的情況下,我認為O(N ^ 2)可能足夠快。

關鍵的見解是:

如果一個B時,它是 “配合到B”。 如果a不除c ,則表示“ a不適合c ”。 如果無法放入C,那么B無法放入C(想象若B安裝到C, 因為裝配到B, 然后將融入所有B的配合到C將不得不也適合c ..(想想主要因子化等))

這意味着我們可以優化。 如果我們將數字從最小到最大排序,首先從較小的數字開始。 第一次迭代中,開始用最小數作為如果我們的數字分成兩組,第1組,人數其中分頻和2其中不分組,那么我們知道,在組沒有數字1罐分割數在2組,因為在第2組沒有數字具有作為一個因素。

所以,如果我們有[2,3,4,5,6,7],我們將從2開始並獲得:[2,4,6]和[3,5,7]我們可以在每個組重復該過程,分成小組。 這表明一種算法可以更有效地計算三元組。 這些組很快就會非常小,這意味着它的效率應該非常接近輸出的大小。

這是迄今為止我能夠提出的最佳答案。 它速度快,但速度不夠快。 我還在發帖,因為我可能會放棄這個問題,不想遺漏任何進展。

def answer(l):
    num_dict = {}
    ans_set = set()

    for a2, a in enumerate(l):
        num_dict[(a, a2)] = []

    for x2, x in enumerate(l):
        for y2, y in enumerate(l):
            if (y, y2) != (x, x2) and y % x == 0:
                pair = (y, y2)
                num_dict[(x, x2)].append(pair)

    for x in num_dict:
        for y in num_dict[x]:
            for z in num_dict[y]:
                ans_set.add((x[0], y[0], z[0]))

    return len(ans_set)

暫無
暫無

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

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