这两个问题试图找到x
和y
两个元素,x+y=target
。这可以使用强力方法来实现。
for x in arr:
for y in arr:
if x+y==target:
return [x,y]
我们正在for循环中进行一些冗余计算 - 也就是说我们只想考虑两个元素的组合。我们可以按如下方式进行N C 2
双循环。
for i, x in enumerate(arr):
if y in arr[i+1:]:
if x+y==target:
return [x,y]
我们节省了很大的时间复杂因素。现在让我们注意,内部循环是一个搜索。我们可以使用哈希搜索或二进制搜索。
seen = set()
for i, x in enumerate(arr):
if target-x in seen:
y = target-x
return [x,y]
seen.add(x)
并非只看到i
的长度。它只会在击中第二个数字时触发(因为它的补码必须在集合中)。
此问题的一个变体是:查找满足以下x-y = target
的元素。这是一个简单的变体,但它为这个问题增加了一点逻辑复杂性。
我的问题是:为什么以下不起作用?也就是说,我们只是修改了以前的代码?
seen = set()
for i, x in enumerate(arr):
for x-target in seen:
y = x-target
return [x,y]
seen.add(x)
我问过一个朋友,但是我不理解他。他说减法不是联想的。我们在二和问题中利用加法的关联性来实现恒定的时间改进。但这就是他告诉我的全部。老实说我不明白。我仍然认为我的代码应该有效。有人能告诉我为什么我的代码不起作用吗?
答案 0 :(得分:0)
您的算法(一旦if
/ for
混合被修复)仍然不起作用,因为减法不是可交换的。该算法仅有效地检查x
,y
对,其中x
在数组中的位置比y
更晚。在测试x+y = target
时没关系,因为这两个值的顺序无关紧要。但对于x-y = target
,顺序确实很重要,因为x - y
不是同一个y - x
。
对此的修复方法是检查数组中的每个数字,看看它是x
还是y
,而另一个值是来自arr
的早期值之一。每个都需要进行不同的检查,因此在循环中可能需要两个if
语句:
seen = set()
for n in arr:
if n-target in seen:
x = n
y = n-target
return [x,y]
if n+target in seen:
x = n+target
y = n
return [x,y]
seen.add(x)
请注意,我将循环变量重命名为n
,因为它可能是x
或y
,具体取决于算法的运算方式。在x
语句的主体中使用y
和if
变量并非绝对必要,您可以直接在return
语句中进行这些计算。我还删除了不需要的enumerate
调用,因为代码的单循环版本根本不使用i
。