Codility: An activity selection problem about scheduling two enemies to watch movies at a festival I don't remember the exact wording of the question, but it is clearly an activity selection problem, which is


  [...] notable in that using a greedy algorithm to find a solution will always result in an optimal solution.


I put a rough description of the problem in the docstring, and present it together with my solution:

def solution(movies, K, L):
    """
    Given two integers K and L, and a list movies where the value at the ith index 
    represents the number of movies showing on the (i + 1)th day at the festival, returns 
    the maximum number of movies that can be watched in two non-overlapping periods of K and 
    L days, or -1 if no two such periods exist.
    """
    kl_days = [
        sum(movies[k_start:k_start + K] + movies[l_start:l_start + L])
        for k_start in range(len(movies) - K)
        for l_start in range(k_start + K, len(movies) - L + 1)
    ]
    lk_days = [
        sum(movies[k_start:k_start + K] + movies[l_start:l_start + L])
        for l_start in range(len(movies) - L)
        for k_start in range(l_start + L, len(movies) - K + 1)
    ]
    days = [-1] + kl_days + lk_days
    return max(days)


Is there a more elegant way to solve this?

P.S. The function name is fixed for grading purposes.
Your code is probably around the best it can be performance wise. And so there's not much point splitting hairs finding anything better.

However you should be able to find something that uses less memory. Something about \$O(L + K)\$ rather than \$O(M^2)\$
I'd split finding indexes, and sums into two separate functions.
Your code, to me, looks slightly wrong.


range(l_start + L, len(movies) - K + 1)



Should probably be:

range(l_start + L, len(movies) - K)

Finally I'd split your code into two more functions, one that performs the sum, and then one that performs the max.


And so I'd change your code to:

def _solution_indexes(movies, K, L):
    for k in range(movies - K):
        for l in range(k + K, movies - L):
            yield k, l

    for l in range(movies - L):
        for k in range(l + L, movies - K):
            yield k, l

def solution_(movies, K, L):
    for k, l in _solution_indexes(len(movies), K, L):
        yield sum(movies[k:k + K]) + sum(movies[l:l + L])

def solution(movies, K, L):
    return max(solution_(movies, K, L), default=-1)