简体   繁体   中英

How do I check if the given number is the sum of a list slice?

I have a python list consist of integers. I need to find whether the given number is sum(mylist[some slice])

a = [1, 2, 2, 3, 3, 5, 5, 6, 6]
num = 22
Answer will be either [3, 3, 5, 5, 6] or [5, 5, 6, 6]
#'.' sum([3, 3, 5, 5, 6]) == 22 || sum([5, 5, 6, 6]) == 22

So far I have done something like a recursive way. Note: I am getting the expected output

def find_slice(mylist, num, extra=2):
    if len(mylist) == 0:
        return None

    for i in range( len(mylist )-1):
        if sum( mylist[:extra + i] ) == num:
            return mylist[ :extra + i]

    return find_slice(mylist[1:], num, extra+1)

>>> a = [1, 2, 2, 3, 3, 5, 5, 6, 6]

>>> print(find_slice(a, 22))
[3, 3, 5, 5, 6]

In terms of time complexity, it takes O(n!) (N factorial) .

How can I modify this in terms of time complexity and space complexity ? Or Is there any better approach?

you can use a window while you are iterating over your items:

a = [1, 2, 2, 3, 3, 5, 5, 6, 6]
num = 22
def find_slice(mylist, num):
    window = []
    for e in a:
        window.append(e)
        s = sum(window)

        if s > num:
            window.pop(0)
            while sum(window) > num:
                window.pop(0)
            s = sum(window)

        if s == num:
            return window

print(find_slice(a, num))
# [3, 3, 5, 5, 6]

this will be O(n) time complexity and O(n) space

Adding to @kederrac's sliding window solution, its worth mentioning that popping the first item with pop(0) is O(N) , whereas popping the last item from the end with pop(-1) is O(1) . We can see this comparison in the Time Complexity - Python Wiki .

We can make popping the first item O(1) using popleft from collections.deque :

Remove and return an element from the left side of the deque. If no elements are present, raises an IndexError.

Modified code:

from collections import deque

a = [1, 2, 2, 3, 3, 5, 5, 6, 6]
num = 22

def find_slice(mylist, num):
    window = deque() 
    for e in a:
        window.append(e)
        s = sum(window)

        if s > num:
            window.popleft()
            while sum(window) > num:
                window.popleft()
            s = sum(window)

        if s == num:
            return window

print(list(find_slice(a, num)))
# [3, 3, 5, 5, 6]

The solution above should now be approximately O(N * W) , where N is the number of elements in the list, and W is the window size. I don't think you can get much better than this.

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