简体   繁体   中英

Find Triplets smaller than a given number

I am trying to solve a problem where:

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]

My algorithm: Remove a single element from the list, set target = target - number_1, search for doublets such that number_1 + number _2 < target - number_1. Problem solved.

The problem link is https://leetcode.com/problems/3sum-smaller/description/ .

My solution is:

    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

My solution fails:

Input:
[1,1,-2]
1
Output:
3
Expected:
1

I am not getting why is the error there as my solution passes more than 30 test cases.

Thanks for your help.

One main point is that when you sort the elements in the first line, you also lose the indexes. This means that, despite having found a triplet, you'll never be sure whether your (i, j, k) will satisfy condition 1, because those (i, j, k) do not come from the original list, but from the new one.

Additionally: everytime you pluck an element from the middle of the array, the remaining part of the array is also iterated (although in an irregular way, it still starts from the first of the remaining elements in tmp ). This should not be the case! I'm expanding details:

The example iterates 3 times over the list (which is, again, sorted and thus you lose the true i, j, and k indexes):

  • First iteration ( i = 0, tmp = [1, -2], t = 0 ). When you sum temp[l] + temp[r] ( l, r are 0, 1 ) it will be -1 . It satisfies being lower than t . smaller will increase.
  • The second iteration will be like the first, but with i = 1 . Again it will increase.
  • The third one will increase as well, because t = 3 and the sum will be 2 now.

So you'll count the value three times (despite only one tuple can be formed in order of indexes) because you are iterating through the permutations of indexes instead of combinations of them. So those two things you did not take care about:

  • Preserving indexes while sorting.
  • Ensuring you iterate the indexes in a forward-fashion only.

Try like this better:

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

Seems like you're counting the same triplet more than once ...

In the first iteration of the loop, you omit the first 1 in the list, and then increase smaller by 1 . Then you omit the second 1 in the list and increase smaller again by 1 . And finally you omit the third element in the list, -2 , and of course increase smaller by 1 , because -- well -- in all these three cases you were in fact considering the same triplet {1,1,-2} .

ps It seems like you care more about correctness than performance. In that case, consider maintaining a set of the solution triplets, to ensure you're not counting the same triplet twice.

There are already good answers , Apart that , If you want to check your algorithm result then you can take help of this in-built funtion :

import itertools

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

output:

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

output:

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

if you want only count then:

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

output:

2

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM