链表算法查找总和为 10 的对
您能否建议一种算法来查找链表中加起来为 10 的所有节点对。 我想出了以下内容。
算法:从第二个节点开始比较每个节点,每个节点从头节点开始直到前一个节点(在当前比较的节点之前)并报告所有此类对。
我认为这个算法应该可以工作,但是它肯定不是最有效的算法,复杂度为 O(n2)。
任何人都可以暗示一个更有效的解决方案(可能需要线性时间)。这种解决方案可以使用附加或临时节点。
Can you suggest an algorithm that find all pairs of nodes in a link list that add up to 10.
I came up with the following.
Algorithm: Compare each node, starting with the second node, with each node starting from the head node till the previous node (previous to the current node being compared) and report all such pairs.
I think this algorithm should work however its certainly not the most efficient one having a complexity of O(n2).
Can anyone hint at a solution which is more efficient (perhaps takes linear time). Additional or temporary nodes can be used by such a solution.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果它们的范围有限(例如 -100 到 100 之间),则很容易。
创建一个数组
quant[-100..100]
然后循环遍历链表,执行:然后下面的循环就可以了。
即使它们的范围不受限制,您也可以拥有比您建议的方法更有效的方法,方法是首先对值进行排序,然后仅保留计数而不是单个值(与上述解决方案相同)。
这是通过运行两个指针来实现的,一个在列表的开头,一个在列表的末尾。当这些指针处的数字加起来为 10 时,输出它们,并将结束指针向下移动,开始指针向上移动。
当它们大于 10 时,将结束指针向下移动。当它们较小时,将起始指针向上移动。
这依赖于排序的性质。小于 10 意味着您需要使总和更高(向上移动起始指针)。大于 10 意味着您需要减少总和(结束指针向下)。由于它们在列表中不重复(由于计数),因此等于 10 意味着您移动了两个指针。
当指针互相经过时停止。
还有一个棘手的问题,那就是当指针相等且值之和为 10 时(显然,只有当值为 5 时才会发生这种情况)。
您不会根据乘积输出对的数量,而是根据值减 1 的乘积来输出。这是因为计数为 1 的值 5 实际上并不等于 10(因为只有一个 5)。
因此,对于列表:
您将得到:
p1
起始于a
,将p2
起始于h
。由于-1 + 11 = 10
,您输出这两个数字(如上所述,您执行N
次,其中N
是数)。这是(-1,11)
的一份副本。然后将p1
移动到b
,将p2
移动到g
。1 + 10 > 10
因此将p1
保留在b
处,将p2
向下移动到f
。p1
移至c
,将p2
保留在f
处。p1
移至d
,将p2
保留在f
处。3 + 7 = 10
,输出两份(3,7)
,因为d
的计数为2,移动p1< /code> 到
e
,p2
到e
。5 + 5 = 10
但是p1 = p2
所以乘积是 0 乘以 0 或 0。什么也不输出,移动p1 到
f
,p2
到d
。p1 > 开始结束p2
。因此,总体输出是:
这是正确的。
这是一些测试代码。您会注意到我已将 7(中点)强制设置为特定值以进行测试。显然,你不会这样做。
您会看到上面的代码都是 O(n),因为我没有在此版本中进行排序,只是智能地使用值作为索引。
如果最小值低于零(或非常高到会浪费太多内存的程度),您可以使用 minVal 来调整索引(另一个 O(n) 扫描来查找最小值,然后只需使用
i-minVal
而不是数组索引的i
)。而且,即使从低到高的范围对内存来说太昂贵,您也可以使用稀疏数组。您必须对其进行排序,O(n log n),并搜索它以获取更新计数,也是 O(n log n),但这仍然比原始 O(n2) 更好。二分搜索的复杂度为 O(n log n) 是因为单个搜索的复杂度为 O(log n),但您必须对每个值都执行此操作。
这是测试运行的输出,它向您展示了计算的各个阶段。
<代码>
If their range is limited (say between -100 and 100), it's easy.
Create an array
quant[-100..100]
then just cycle through your linked list, executing:Then the following loop will do the trick.
Even if their range isn't limited, you can have a more efficient method than what you proposed, by sorting the values first and then just keeping counts rather than individual values (same as the above solution).
This is achieved by running two pointers, one at the start of the list and one at the end. When the numbers at those pointers add up to 10, output them and move the end pointer down and the start pointer up.
When they're greater than 10, move the end pointer down. When they're less, move the start pointer up.
This relies on the sorted nature. Less than 10 means you need to make the sum higher (move start pointer up). Greater than 10 means you need to make the sum less (end pointer down). Since they're are no duplicates in the list (because of the counts), being equal to 10 means you move both pointers.
Stop when the pointers pass each other.
There's one more tricky bit and that's when the pointers are equal and the value sums to 10 (this can only happen when the value is 5, obviously).
You don't output the number of pairs based on the product, rather it's based on the product of the value minus 1. That's because a value 5 with count of 1 doesn't actually sum to 10 (since there's only one 5).
So, for the list:
you get:
p1
ata
andp2
ath
. Since-1 + 11 = 10
, you output those two numbers (as above, you do itN
times whereN
is the product of the counts). Thats one copy of(-1,11)
. Then you movep1
tob
andp2
tog
.1 + 10 > 10
so leavep1
atb
, movep2
down tof
.1 + 7 < 10
so movep1
toc
, leavep2
atf
.2 + 7 < 10
so movep1
tod
, leavep2
atf
.3 + 7 = 10
, output two copies of(3,7)
since the count ofd
is 2, movep1
toe
,p2
toe
.5 + 5 = 10
butp1 = p2
so the product is 0 times 0 or 0. Output nothing, movep1
tof
,p2
tod
.p1 > p2
.Hence the overall output was:
which is correct.
Here's some test code. You'll notice that I've forced 7 (the midpoint) to a specific value for testing. Obviously, you wouldn't do this.
You'll see that the code above is all O(n) since I'm not sorting in this version, just intelligently using the values as indexes.
If the minimum is below zero (or very high to the point where it would waste too much memory), you can just use a minVal to adjust the indexes (another O(n) scan to find the minimum value and then just use
i-minVal
instead ofi
for array indexes).And, even if the range from low to high is too expensive on memory, you can use a sparse array. You'll have to sort it, O(n log n), and search it for updating counts, also O(n log n), but that's still better than the original O(n2). The reason the binary search is O(n log n) is because a single search would be O(log n) but you have to do it for each value.
And here's the output from a test run, which shows you the various stages of calculation.
创建一个哈希集(Java 中的 HashSet)(如果您的数字有界,则可以使用稀疏数组,即您知道它们落入 +/- 100 范围内)
对于每个节点,首先检查 10-n 是否在集合中。如果是这样,您就找到了一对。无论哪种方式,然后将 n 添加到集合中并继续。
例如你有
1 - 6 - 3 - 4 - 9
1 - 9 在集合中吗?不是
6-4吗? ?
3-7号 ?
4-6号 是的!打印 (6,4)
9 - 1?是的!打印 (9,1)
Create a hash set (HashSet in Java) (could use a sparse array if your numbers are well-bounded, i.e. you know they fall into +/- 100)
For each node, first check if 10-n is in the set. If so, you have found a pair. Either way, then add n to the set and continue.
So for example you have
1 - 6 - 3 - 4 - 9
1 - is 9 in the set? Nope
6 - 4? No.
3 - 7? No.
4 - 6? Yup! Print (6,4)
9 - 1? Yup! Print (9,1)
这是一个 NP 完全的迷你子集和问题。
This is a mini subset sum problem, which is NP complete.
如果您首先对集合进行排序,则会消除需要评估的数字对。
If you were to first sort the set, it would eliminate the pairs of numbers that needed to be evaluated.