一圈?python
所以我写了这个函数,它是给定可能数的,它必须找到组成给定数的可能数中的两个数。然而,我仍在学习Python(一种非常出色的语言),因此我只能使用有限的函数集 我创建了这个函数:一圈?python,python,Python,所以我写了这个函数,它是给定可能数的,它必须找到组成给定数的可能数中的两个数。然而,我仍在学习Python(一种非常出色的语言),因此我只能使用有限的函数集 我创建了这个函数: def sumPair(theList, n): theList = charCount(theList) #charCount is a function i made to convert the list into a dictionary for i in theList: fo
def sumPair(theList, n):
theList = charCount(theList) #charCount is a function i made to convert the list into a dictionary
for i in theList:
for a,b in theList.iteritems():
print a,b
if a + i == n:
if theList[b] > 1:
return [i, b]
if a != i:
return [i, b]
return "[]"
print sumPair([6,3,6,8,3,2,8,3,2], 11)
就像我说的,它会找到两个和给定数字相加的数字charCount
是我编写的一个函数,它将数组添加到字典中
在这个程序中,我确保在所加的数字相同的情况下,该值大于1。有时,如果它检查10的和,你给它一个5的数字,它只会将5加到它自己,然后返回10。这就是为什么如果列表[b]>1:
有
我为什么在这里?我的教练对两个循环不满意。我花了5个小时排除故障,结果一无所获。我需要把这个程序转换成一个单循环程序
我花了一整天在这上面,我不是想让你做作业,我只是真的被卡住了,我需要你的帮助。我听说我应该检查是否存在一个密钥来完成这项任务。教员可能不满意您的算法花费的时间比必须花费的时间更长。试试这个:
for each element x in theList
if there exists an element y in theList such that x+y = n, you have a match
您需要快速进行“if exists”测试,这就是您使用字典的目的。一个循环将建立此词典,第二个循环将搜索整个词典。与O(n^2)时间相比,这需要线性时间
你关于5点与自身匹配的观点是正确的。您希望使用称为multiset或bag的数据结构。阅读相关内容,然后以以下方式实现代码:
for each element x in theList
if there exists an element y in theList such that x+y == n:
if x != y or (x == y and x occurs more than once):
you have a match
祝你好运
编辑,因为有太多次优解,这里是简单的线性解(它是线性的,因为列表中有两个循环,但是循环一个接一个地出现。因此,2*n次迭代,O(n)。它非常快
#!/usr/bin/python2.6
from collections import defaultdict
def sum_list(l, n):
count = defaultdict(lambda: 0)
for x in l: # O(n)
count[x] += 1 # This can be done in constant time O(1)
for x in l: # O(n)
y = n - x
if count[y] > 0 and (x != y or count[y] > 1): # O(1)
return x, y
我的评论:
- 如果将列表转换为字典,请将名称从
更改为其他名称。如果有一个名为theList
的变量保存字典,则会造成混淆theList
- 如果这两个数字总是相邻,您可以尝试编写一个循环,将索引变量
设置为0,然后递增i
,检查i
是否等于所需的数字list[i]+list[i+1]
- 如果这两个数字可能不相邻,那么就比较棘手了。最明显的方法是使用两个循环:一个循环依次查看每个数字,另一个循环查看下面的数字,看看它们是否等于目标值。如果这两个数字不必相邻,并且讲师希望您只使用一个循环,然后,您需要使用一些东西来保存列表值(比如字典),或者可能使用“隐式循环”
,它将告诉您对象是否在Python列表中。它通过循环列表来工作,但您不编写循环;循环是在Python内部为您完成的
因此,您可以这样做:依次查看每个数字。从目标值中减去数字,然后在
中使用,查看计算值是否在列表的其余部分。要搜索列表的其余部分并跳过当前值,请使用“列表切片”.如果你还没有学会切片,你的指导老师可能不是在寻找列表切片的答案
下面是一个示例。如果将i
设置为0,并且查看列表中的第一个条目,则值为6。目标值为11。因此计算值为(11-6)或者5.然后检查列表中是否有computed\u值
。要仅查看列表的其余部分,可以使用切片,然后在列表中有computed\u值[1:
。如果有索引变量i
,则类似于computed\u值=11-列表[i]
然后检查列表[i:]
中的计算值
- 不要忘记,可以使用
for
循环来创建从0到列表长度的索引,并使用索引索引到列表中。在Python中,通常最好在lst:
中使用for x,它将x
设置为列表中的连续对象,但有时在使用时会遇到问题ul对xrange中的i使用(len(lst)):
,然后使用lst[i]
或lst[i+1]
或lst[i:
或其他任何东西
使用老师想要的任何编码样式。如果老师想要像“theList”这样的“camelCase”名称,那么就这样做。但是Python的常用样式称为“pep8”,并且该样式中的变量名是小写加下划线的,如“theu list”
纯python-未使用库:
def combinations(lst):
l = lst[:] # copy of source list
while len(l) > 1:
a = l.pop(0)
for b in l:
yield a,b
def first_pair(iterator):
for i in iterator:
# just return first element
return i
def sum_pair(lst, sum_val):
return first_pair((a,b) for a,b in combinations(lst) if (a+b) == sum_val)
print sum_pair([6,3,6,8,3,2,8,3,2], 11)
# result (3,8)
使用itertools:
from itertools import combinations, islice
def sum_pair(lst, sum_val):
return list(islice(((a,b)
for a,b in combinations(lst, 2) if (a+b) == sum_val), 0, 1))
print sum_pair([6,3,6,8,3,2,8,3,2], 11)
# result [(3,8)]
思考这个问题总是有帮助的,我应该如何用手,用铅笔和纸,甚至只看纸上的一行数字。然而,更好的解决方案一开始可能看起来过于复杂,它们的优势一开始可能并不那么明显——看(他的答案是我个人的赢家,见下文)
首先,您需要将一个数字与所有其他数字进行比较。然后将第二个数字与其他数字进行比较,等等。当使用朴素方法时,在使用单个进程时,无法避免两个嵌套循环。然后时间复杂度始终为O(n^2)其中,n是序列的长度。事实上,一些循环可能隐藏在操作中,如
中的或list.index()
,这在原则上不会使解决方案变得更好
想象一下数字的笛卡尔积——它由数对组成。有n^2对这样的数对,但大约有一半是关于加法运算的可换性的,n的
for each first element in theList:
for each second element in the rest of theList from the checked one on:
if the first and the second elements give the solution:
report the result
possibly early break if only the first should be reported
def sumPair(theList, n):
for index, e in enumerate(theList): # to know the index for the slicing below
complement = n - e # we are searching for the complement
if complement in theList[index+1:]: # only the rest is searched
return e, complement
print sumPair([6,3,6,8,3,2,8,3,2], 11)
def sumPair2(theList, n):
for ind, e in enumerate(theList):
try:
theList.index(n - e, ind + 1)
return e, n - e
except ValueError:
pass
import timeit
def sumPair(theList, n):
for index, e in enumerate(theList):
if n - e in theList[index+1:]:
return e, n - e
def sumPair2(theList, n):
for ind, e in enumerate(theList):
try:
theList.index(n - e, ind + 1)
return e, n - e
except ValueError:
pass
def sumPair_gnibbler(theList, n):
# If n is even, check whether n/2 occurs twice or more in theList
if n%2 == 0 and theList.count(n/2) > 1:
return n/2, n/2
theSet = set(theList)
for e in theSet:
if n - e in theSet:
return e, n - e
theList = [6,3,6,8,3,2,8,3,2]
n = 11
print '---------------------', n
print sumPair(theList, n),
print timeit.timeit('sumPair(theList, n)', 'from __main__ import sumPair, theList, n', number = 1000)
print sumPair2(theList, n),
print timeit.timeit('sumPair2(theList, n)', 'from __main__ import sumPair2, theList, n', number = 1000)
print sumPair_gnibbler(theList, n),
print timeit.timeit('sumPair_gnibbler(theList, n)', 'from __main__ import sumPair_gnibbler, theList, n', number = 1000)
n = 1
print '---------------------', n
print sumPair(theList, n),
print timeit.timeit('sumPair(theList, n)', 'from __main__ import sumPair, theList, n', number = 1000)
print sumPair2(theList, n),
print timeit.timeit('sumPair2(theList, n)', 'from __main__ import sumPair2, theList, n', number = 1000)
print sumPair_gnibbler(theList, n),
print timeit.timeit('sumPair_gnibbler(theList, n)', 'from __main__ import sumPair_gnibbler, theList, n', number = 1000)
--------------------- 11
(3, 8) 0.00180958639191
(3, 8) 0.00594907526295
(8, 3) 0.00124991060067
--------------------- 1
None 0.00502748219333
None 0.026334041968
None 0.00150958864789
theList = range(10000)
n = 11
print '---------------------', n
print sumPair(theList, n),
print timeit.timeit('sumPair(theList, n)', 'from __main__ import sumPair, theList, n', number = 100)
print sumPair2(theList, n),
print timeit.timeit('sumPair2(theList, n)', 'from __main__ import sumPair2, theList, n', number = 100)
print sumPair_gnibbler(theList, n),
print timeit.timeit('sumPair_gnibbler(theList, n)', 'from __main__ import sumPair_gnibbler, theList, n', number = 100)
n = 3000
print '---------------------', n
print sumPair(theList, n),
print timeit.timeit('sumPair(theList, n)', 'from __main__ import sumPair, theList, n', number = 100)
print sumPair2(theList, n),
print timeit.timeit('sumPair2(theList, n)', 'from __main__ import sumPair2, theList, n', number = 100)
print sumPair_gnibbler(theList, n),
print timeit.timeit('sumPair_gnibbler(theList, n)', 'from __main__ import sumPair_gnibbler, theList, n', number = 100)
n = 30000
print '---------------------', n
print sumPair(theList, n),
print timeit.timeit('sumPair(theList, n)', 'from __main__ import sumPair, theList, n', number = 100)
print sumPair2(theList, n),
print timeit.timeit('sumPair2(theList, n)', 'from __main__ import sumPair2, theList, n', number = 100)
print sumPair_gnibbler(theList, n),
print timeit.timeit('sumPair_gnibbler(theList, n)', 'from __main__ import sumPair_gnibbler, theList, n', number = 100)
--------------------- 11
(0, 11) 0.00840137682165
(0, 11) 0.00015695881967
(0, 11) 0.089894683992
--------------------- 3000
(0, 3000) 0.0166750746034
(0, 3000) 0.00966040735374
(0, 3000) 0.12532849753
--------------------- 30000
None 180.328006493
None 163.651082944
None 0.204691100723
def sumPair(theList, n):
# If n is even, check whether n/2 occurs twice or more in theList
if n%2 == 0 and theList.count(n/2) > 1:
return [n/2, n/2]
theSet = set(theList)
for i in theSet:
if n-i in theSet:
return [i, n-i]
return []
def get_sum_pairs(sum = None, list_of_numbers = None):
assert sum != None and list_of_numbers != None
list_of_numbers = sorted(list_of_numbers) # sort the list of numbers O(n log n)
for index, number in enumerate(list_of_numbers): # search for each number that is less than the sum O(n)
if number < sum: # if number greater then sum, theres nothing we can do.
for index, number_1 in enumerate(list_of_numbers[(index + 1):]): # search the second list, this isn't exactly O(n) since its incremented being incremented
if number + number_1 == sum: # found a solution.
return [(number, number_1)]
if (number_1 > sum) or (number + number_1 > sum): # if number greater then sum, theres nothing we can do.
break # if the addition of two sorted numbers is greater then sum, then theres no need to keep searching since the rest will also be greater, since their sorted.
else:
break
return [()]
assert all([get_sum_pairs(**test[0]) == test[1] for test in
[({'list_of_numbers':[6,3,6,8,3,2,8,3,2], 'sum':11}, [(3, 8)]),
({'list_of_numbers':[1,2,3,4,1,2], 'sum':1}, [()]),
({'list_of_numbers':[1,2,3,1,23,1,23,123], 'sum':124}, [(1, 123)]),
({'list_of_numbers':[1,2,3,12,3,2,1,23,4,1,23,4,5,12332], 'sum':14}, [(2, 12)]),
({'list_of_numbers':[-1,2,-2, -3, 1, 2, 3, 2, -1.3], 'sum':1}, [(-1, 2)])
] ])
def sumpairs(numbers, n):
numbers = [None] + numbers + [None] * (n-len(numbers))
for k in range(len(numbers)):
a = numbers[k]
if a is None or a==k: continue
if numbers[n-a]==n-a:
return a, n-a
numbers[k] = None
while numbers[a] != a and a is not None:
b = n-a
if numbers[a] is None:
numbers[a] = a
break
if numbers[b]==b:
return a, n-a
numbers[a], a = a, numbers[a]
print(sumpairs([6,3,6,8,3,2,8,3,2], 16))
print(sumpairs([6,3,6,8,3,2,8,3,2], 11))
print(sumpairs([6,3,5,8,3,2,8,3,2], 10))
print(sumpairs([6,3,5,8,3,2,8,3,2], 5))
print(sumpairs([6,3,5,8,3,2,8,3,2], 12)) # This should fail.
def sumpairs(numbers, n):
numbers = sorted(numbers)
low = 0
while low < len(numbers)-1:
t = numbers[low] + numbers[-1]
if t > n:
numbers.pop(-1)
elif t < n:
low += 1
else:
return numbers[low], numbers[-1]
print(sumpairs([6,3,6,8,3,2,8,3,2], 16))
print(sumpairs([6,3,6,8,3,2,8,3,2], 11))
print(sumpairs([6,3,5,8,3,2,8,3,2], 10))
print(sumpairs([6,3,5,8,3,2,8,3,2], 5))
print(sumpairs([6,3,5,8,3,2,8,3,2], 12)) # This should fail.