关于python:查找小于给定数字的三胞胎

Find Triplets smaller than a given number

我试图解决一个问题,其中:

Given an array of n integers nums and a target, find the number of
index triplets i, j, k with 0 <= i < j < k < n that satisfy the condition nums[i] + nums[j] + nums[k] < target.

For example, given nums = [-2, 0, 1, 3], and target = 2.

Return 2. Because there are two triplets which sums are less than 2:

[-2, 0, 1] [-2, 0, 3]

我的算法:从列表中删除一个元素,设置target=target-number_,搜索doublets,使number_+number_

问题链接是https://leetcode.com/problems/3sum-smaller/description/。

我的解决方案是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
    def threeSumSmaller(nums, target):
       """
        :type nums: List[int]
        :type target: int
        :rtype: int
       """


        nums = sorted(nums)
        smaller = 0

        for i in range(len(nums)):

            # Create temp array excluding a number

            if i!=len(nums)-1:
                temp = nums[:i] + nums[i+1:]

            else:
                temp = nums[:len(nums)-1]


            # Sort the temp array and set new target to target - the excluded number

            l, r = 0, len(temp) -1
            t = target - nums[i]

            while(l<r):

                if temp[l] + temp[r] >= t:

                    r = r - 1

                else:

                    smaller += 1

                    l = l + 1


        return smaller

我的解决方案失败:

1
2
3
4
5
6
7
Input:
[1,1,-2]
1
Output:
3
Expected:
1

我不明白为什么当我的解决方案通过30多个测试用例时会出现错误。

谢谢你的帮助。


一个要点是,当对第一行中的元素进行排序时,也会丢失索引。这意味着,尽管已经发现了一个三联体,但你永远无法确定你的(i, j, k)是否满足条件1,因为这些(i, j, k)不是来自原始列表,而是来自新列表。

另外:每次从数组中间提取元素时,数组的其余部分也会重复(虽然不规则,但它仍然从tmp中的其余元素的第一个开始)。情况不应该是这样的!我正在扩展细节:

该示例在列表上迭代3次(再次排序,这样会丢失真正的I、J和K索引):

  • 第一次迭代(i = 0, tmp = [1, -2], t = 0)。当你把temp[l] + temp[r](l, r0, 1时,它就是-1。满足低于t的要求。smaller将增加。
  • 第二次迭代和第一次一样,但是使用i = 1。它会再次增加。
  • 第三个也会增加,因为现在t = 32

因此,您将对值进行三次计数(尽管按照索引的顺序只能形成一个元组),因为您正在迭代索引的排列,而不是它们的组合。所以你不关心的两件事是:

  • 排序时保留索引。
  • 确保只以正向方式迭代索引。

最好这样做:

1
2
3
4
5
6
7
8
9
10
11
def find(elements, upper_bound):
    result = 0
    for i in range(0, len(elements) - 2):
        upper_bound2 = upper_bound - elements[i]
        for j in range(i+1, len(elements) - 1):
            upper_bound3 = upper_bound2 - elements[j]
            for k in range(j+1, len(elements)):
                upper_bound4 = upper_bound3 - elements[k]
                if upper_bound4 > 0:
                    result += 1
    return result

已经有了很好的答案,除此之外,如果您想检查您的算法结果,那么您可以利用内置功能:

1
2
3
4
5
6
7
8
import itertools

def find_(vector_,target):
    result=[]
    for i in itertools.combinations(vector_, r=3):
        if sum(i)<target:
            result.append(i)
    return result

输出:

1
print(find_([-2, 0, 1, 3],2))

输出:

1
[(-2, 0, 1), (-2, 0, 3)]

如果只想计数,那么:

1
print(len(find_([-2, 0, 1, 3],2)))

输出:

1
2


好像你不止一次的数同一个三倍体…

在循环的第一次迭代中,您省略了列表中的第一个1,然后用1增加smaller。然后省略列表中的第二个1,再增加smaller。最后你省略了列表中的第三个元素,-2,当然增加了smaller,增加了1,因为——好吧——在这三种情况下,你实际上考虑的是相同的三重{1,1,-2}

另外,似乎你更关心的是正确性而不是性能。在这种情况下,考虑维护一组解决方案三元组,以确保不将同一个三元组计数两次。