Ich mag dieses Problem, weil es so viele Möglichkeiten gibt, es umzusetzen. Ich habe beschlossen, eine Referenzantwort für die Zukunft zu erstellen.
Was soll in der Produktion verwendet werden?
Die Dokumentation von intertools enthält ein in sich geschlossenes Beispiel, warum sollten Sie es nicht in Ihrem Code verwenden? Einige Leute schlugen die Verwendung von more_itertools.powerset
aber es hat genau die gleiche Umsetzung ! An Ihrer Stelle würde ich nicht das ganze Paket wegen einer Kleinigkeit installieren. Wahrscheinlich ist dies der beste Weg zu gehen:
def powerset(iterable):
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
Andere mögliche Ansätze
Ansatz 0: Verwendung von Kombinationen
import itertools
def subsets(nums):
result = []
for i in range(len(nums) + 1):
result += itertools.combinations(nums, i)
return result
Ansatz 1: Geradlinige Rekursion
def subsets(nums):
result = []
def powerset(alist, index, curr):
if index == len(alist):
result.append(curr)
return
powerset(alist, index + 1, curr + [alist[index]])
powerset(alist, index + 1, curr)
powerset(nums, 0, [])
return result
Ansatz 2: Backtracking
def subsets(nums):
result = []
def backtrack(index, curr, k):
if len(curr) == k:
result.append(list(curr))
return
for i in range(index, len(nums)):
curr.append(nums[i])
backtrack(i + 1, curr, k)
curr.pop()
for k in range(len(nums) + 1):
backtrack(0, [], k)
return result
ou
def subsets(nums):
result = []
def dfs(nums, index, path, result):
result.append(path)
for i in range(index, len(nums)):
dfs(nums, i + 1, path + [nums[i]], result)
dfs(nums, 0, [], result)
return result
Ansatz 3: Bitmaskierung
def subsets(nums):
res = []
n = len(nums)
for i in range(1 << n):
aset = []
for j in range(n):
value = (1 << j) & i # value = (i >> j) & 1
if value:
aset.append(nums[j])
res.append(aset)
return res
oder (nicht wirklich Bitmaskierung, sondern die Intuition, dass es genau 2^n Teilmengen gibt)
def subsets(nums):
subsets = []
expected_subsets = 2 ** len(nums)
def generate_subset(subset, nums):
if len(subsets) >= expected_subsets:
return
if len(subsets) < expected_subsets:
subsets.append(subset)
for i in range(len(nums)):
generate_subset(subset + [nums[i]], nums[i + 1:])
generate_subset([], nums)
return subsets
Ansatz 4: Kaskadierung
def subsets(nums):
result = [[]]
for i in range(len(nums)):
for j in range(len(result)):
subset = list(result[j])
subset.append(nums[i])
result.append(subset)
return result
18 Stimmen
Die Leserinnen und Leser sollten beachten, dass unabhängig davon, ob es sich bei den Listenpunkten um einzigartig ist eine extrem wichtige Überlegung, da viele Algorithmen dann einige Teilmengen überzählen (z. B. 'abccc' -> ['', 'a', 'b', 'c', 'c', 'c', 'ac', 'ac', 'ac', ...]. Eine einfache Abhilfe besteht darin, alle Elemente in eine Menge zu schieben vor ihre Permutationen zu erhalten.
0 Stimmen
@ninjagecko Die Verwendung der Set-Bibliothek ist nicht effizient, da sie im besten Fall O(n) ist. Das Hinzufügen von n Funktionen zu einer Menge ist also tatsächlich O(n^2)!
3 Stimmen
Nach sorgfältiger Lektüre der Frage scheint es so, als ob der Fragesteller nach dem PowerSet seiner Liste von 15 Zahlen, nicht alle Kombinationen. Ich glaube, das ist der Grund, warum die Antworten so unterschiedlich ausfallen.
0 Stimmen
@Scott Biggs: Sind Sie sicher, dass Sie sich hier auf Python beziehen? Das Einfügen von Mengen und das Nachschlagen sind O(1) im durchschnittlichen Fall. Sie sind wie Wörterbücher. Sie verwenden Hashing. Python hat keine spezielle Mengenbibliothek (sie ist in der Standardbibliothek enthalten). Wir fügen hier Zahlen ein, keine Funktionen. (Es wäre immer noch ineffizient, O(2^n) Speicher zu verwenden; die richtige Lösung für Leute, die eher Kombinationen als die Potenzmenge wollen, ist eine einfache rekursive Implementierung, oder
product
, usw.)0 Stimmen
Siehe auch stackoverflow.com/questions/10342939/ .