web-dev-qa-db-fra.com

Somme maximale sous-liste?

Je suis confus avec cette question à ce qu'il essaie de demander. 

Écrivez la fonction mssl() (sous-liste de somme minimale) qui prend en entrée une liste des nombres entiers. Il calcule ensuite et renvoie la somme de la somme maximale sous-liste de la liste d'entrée. La somme maximale sous-liste est une sous-liste (tranche) de la liste d'entrées dont la somme d'entrées est la plus grande. Le vide La sous-liste est définie comme ayant la somme 0. Par exemple, la somme maximale sous-liste [4, -2, -8, 5, -2, 7, 7, 2, -6, 5] est [5, -2, 7, 7, 2] et la somme de ses entrées est 19.

Si je devais utiliser cette fonction, elle devrait renvoyer quelque chose de similaire à

>>> l = [4, -2, -8, 5, -2, 7, 7, 2, -6, 5]
>>> mssl(l)
19
>>> mssl([3,4,5])
12
>>> mssl([-2,-3,-5])
0

Comment puis-je le faire?

Voici mon essai actuel, mais cela ne donne pas le résultat attendu:

def mssl(x):
    ' list ==> int '
    res = 0
    for a in x:
        if a >= 0:
            res = sum(x)
        return res
    else:
        return 0
27
Jeff Rageo

Il existe en fait une solution très élégante et très efficace utilisant la programmation dynamique. Cela prend O(1) espace et O(n) temps - cela ne peut pas être battu!

Définissez A comme étant le tableau d'entrée (index zéro) et B[i] comme somme maximale pour toutes les sous-listes se terminant par, sans inclure la position i (c'est-à-dire toutes les sous-listes A[j:i]). Par conséquent, B[0] = 0 et B[1] = max(B[0]+A[0], 0), B[2] = max(B[1]+A[1], 0), B[3] = max(B[2]+A[2], 0), etc. Ensuite, clairement, la solution est donnée simplement par max(B[0], ..., B[n]).

Étant donné que chaque valeur B dépend uniquement de la précédente B, nous pouvons éviter de stocker le tableau entier B, nous donnant ainsi notre garantie d'espace O(1).

Avec cette approche, mssl se réduit à une boucle très simple:

def mssl(l):
    best = cur = 0
    for i in l:
        cur = max(cur + i, 0)
        best = max(best, cur)
    return best

Manifestation:

>>> mssl([3,4,5])
12
>>> mssl([4, -2, -8, 5, -2, 7, 7, 2, -6, 5])
19
>>> mssl([-2,-3,-5])
0

Si vous souhaitez également les index de tranche de début et de fin, vous devez suivre quelques bits d’information supplémentaires (notez que cela reste encore O(1) espace et O(n) temps, c’est juste un peu poilue):

def mssl(l):
    best = cur = 0
    curi = starti = besti = 0
    for ind, i in enumerate(l):
        if cur+i > 0:
            cur += i
        else: # reset start position
            cur, curi = 0, ind+1

        if cur > best:
            starti, besti, best = curi, ind+1, cur
    return starti, besti, best

Cela retourne un Tuple (a, b, c) tel que sum(l[a:b]) == c et c est maximal:

>>> mssl([4, -2, -8, 5, -2, 7, 7, 2, -6, 5])
(3, 8, 19)
>>> sum([4, -2, -8, 5, -2, 7, 7, 2, -6, 5][3:8])
19
54
nneonneo

C'est le problème de sous-tableau maximum . L'algorithme de Kadane peut le résoudre dans l'espace O(n) time et O(1).

def mssl(x):
    max_ending_here = max_so_far = 0
    for a in x:
        max_ending_here = max(0, max_ending_here + a)
        max_so_far = max(max_so_far, max_ending_here)
    return max_so_far
7
Faraz

selon la question, au cas où, si tous les éléments de la liste sont négatifs, il devrait renvoyer la somme maximale sous la forme 'ZERO'

à la place, si vous voulez que la sortie soit au maximum de la sous-matrice (en nombre négatif), le code ci-dessous vous aidera:

In [21]: def mssl(l):
...:     best = cur = l[0]
...:     for i in range(len(l)):
...:         cur = max(cur + l[i], l[i])
...:         best = max(best, cur)
...:     return best

exemples:

In [23]: mssl([-6, -44, -5, -4, -9, -11, -3, -99])
Out[23]: -3
In [24]: mssl([-51, -23, -8, -2, -6])
Out[24]: -2

pour les nombres positifs et négatifs

In [30]: mssl([4, -2, -8, 5, -2, 7, 7, 2, -6, 5])
Out[30]: 19
4
Ganesh_

Ainsi, si vous comprenez ce qu'est une sous-liste (ou une tranche, ce qui peut être supposé être la même chose), la tranche est définie par l'index de début et l'index de fin.

Vous pourriez donc peut-être essayer de parcourir tous les index de début et de fin possibles et calculer la somme correspondante, puis renvoyer la valeur maximale.

Astuce: l'index de démarrage peut varier de 0 à len(given_list)-1. L'index de fin peut être de start_index à len(given_list)-1. Vous pouvez utiliser une boucle imbriquée for pour vérifier toutes les combinaisons possibles.

3
Lev Levitsky

Voici une implémentation en Java, utilisant l’algorithme de Kadane, qui affiche les index de la plus grosse somme. L'implémentation prend O(n) temps et O(1) espace.

public static void maxSumIndexes(int[] a) {

    int size = a.length;
    if(size == 0) return;

    int maxAtIndex = a[0], max = a[0];
    int bAtIndex = 0;
    int b = 0, e = 0;

    for(int i = 1; i < size; i++) {
        maxAtIndex = Math.max(a[i], a[i] + maxAtIndex);
        if(maxAtIndex == a[i])
            bAtIndex = i;

        max = Math.max(max, maxAtIndex);
        if(max == maxAtIndex) {
            e = i;
            b = (b != bAtIndex)? bAtIndex : b;
        }
    }

    System.out.println(b);
    System.out.println(e);
}
3
Skagen

La solution simple consiste à parcourir la liste et à essayer d’ajouter des tranches jusqu’à ce que vous trouviez la meilleure. Ici, j’ai également inclus l’option de renvoyer la sous-liste réelle. Par défaut, c’est False. J'ai utilisé defaultdict à cet effet car il est plus simple que les recherches.

from collections import defaultdict

def mssl(lst, return_sublist=False):
    d = defaultdict(list)
    for i in range(len(lst)+1):
        for j in range(len(lst)+1):
            d[sum(lst[i:j])].append(lst[i:j])
    key = max(d.keys())
    if return_sublist:
        return (key, d[key])
    return key

print mssl([4, -2, -8, 5, -2, 7, 7, 2, -6, 5])
19
print mssl([4, -2, -8, 5, -2, 7, 7, 2, -6, 5], True)
(19, [[5, -2, 7, 7, 2]])

Bonus: Méthode de compréhension de liste:

def _mssl(lst):
    return max( sum( lst[i:j] ) for i in xrange(len(lst)+1) for j in xrange(i, len(lst)+1) )
2
Inbar Rose

Je suppose que c'est la question pour trouver une sous-séquence dans un tableau qui produit la somme maximale. J'ai rencontré ce problème lors de la recherche d'un problème de somme maximale SUBSET. 

L'implémentation Java pour cette question:

public static int maximumSumSubSequence(int[] array) {

    if (null == array) {
        return -1;
    }

    int maxSum = Integer.MIN_VALUE;
    int startIndexFinal = 0;
    int endIndexFinal = 0;
    int currentSum = 0;
    int startIndexCurrent = 0;

    for (int i = 0; i < array.length; i++) {
        currentSum += array[i];

        if (currentSum > maxSum) {
            maxSum = currentSum;
            endIndexFinal = i;
            startIndexFinal = startIndexCurrent;
        }
        if (currentSum <= 0) {
            currentSum = 0;
            startIndexCurrent = i + 1;
        }
    }
    System.out.println("startIndex: " + startIndexFinal + " endIndex: " + endIndexFinal);
    return maxSum;
}
1
Bhumik Thakkar

Il vous demande de choisir une sous-section plus petite de la liste, de sorte que sa somme soit la plus grande.

Si la liste est entièrement positive [1 2 3], alors bien sûr la sous-section avec la somme la plus grande est simplement la somme de la liste entière [1 2 3] qui est 6.

Si la liste est entièrement négative [-1 -2 -3], la sous-section avec la somme la plus élevée n’est rien [] qui contient la somme 0.

Cependant, si la liste contient des points positifs et des points négatifs, la décision est plus difficile.

[1 2 3 -100 3 4 5] vous devriez voir [3 4 5] et renvoyer 12

[1 2 3 -2 3 4 5] vous devriez utiliser tout cela et retourner 16

1
Ric

Je présente une approche basée sur la programmation dynamique. L'idée principale est que, lorsque nous parcourons le tableau, ajouter un nouvel élément à notre somme actuelle devrait soit augmenter la valeur de la somme, soit aller de l'avant avec notre élément actuel et oublier l'ancienne valeur de somme.

Pour prendre en charge les tableaux contenant des valeurs négatives, nous instancions nos variables avec le premier élément du tableau.

def maxSumSubArr(arr):
    cur_sum = best_sum = arr[0]
    for i in range(1, len(arr)):
        cur_sum = max(arr[i], cur_sum+arr[i])
        best_sum = max(best_sum, cur_sum)
    return best_sum

Le temps d'exécution de cette approche est O (n) et la complexité de l'espace est O (1).

Si vous souhaitez que la sortie soit égale à zéro pour les cas où aucun des éléments n'est positif, instanciez les variables cur_sum et best_sum avec 0 et effectuez une itération à partir du premier élément à la place du deuxième élément.

0
Vatsal Srivastava

si quelqu'un cherche une version plus longue d'un code, la voici:

def mesl(lst):
    sub_sum = list()
    row_sum = list()
    for i in range(len(lst)):
        sub_sum = list()
        sub_sum.append(lst[i])
        k = 1
        for j in range(i+1,len(lst)):
            sub_sum.append(sub_sum[k-1] + lst[j])
            k+=1
        row_sum.append(max(sub_sum))      
    sum = max(row_sum)
    if  sum < 0:
        sum = 0
    return sum
0
redx21

Cette distinction n’a sans doute pas d’importance pour le PO, qui semble juste essayer de comprendre comment résoudre le problème, mais j’ai pensé que cela valait la peine de le mentionner:

Les autres solutions ici impliquent de résumer à plusieurs reprises toutes les sous-parties de la liste. Nous pouvons éviter ces sommes répétées en utilisant une programmation dynamique, car bien sûr, si nous connaissons déjà la somme de i à j, nous n'avons pas besoin de les additionner pour obtenir la somme de i à j+1!

C'est-à-dire, faites un tableau 2d des sommes partielles, pour que partsum[i, j] == sum(lst[i:j]). Quelque chose comme (utiliser un dictionnaire car il est plus facile d'indexer avec; un tableau numpy serait tout aussi simple et plus efficace):

import operator

def mssl(lst, return_sublist=False):
    partsum = { (0, 0): 0 }  # to correctly get empty list if all are negative
    for i in xrange(len(lst) - 1):  # or range() in python 3
        last = partsum[i, i+1] = lst[i]
        for j in xrange(i+1, len(lst)):
            last = partsum[i, j+1] = last + lst[j]

    if return_sublist:
        (i, j), sum = max(partsum.iteritems(), key=operator.itemgetter(1))
        return sum, lst[i:j]

    return max(partsum.itervalues())  # or viewvalues() in 2.7 / values() in 3.x

Cela prend O (n ^ 2) temps et mémoire, par opposition à O (n ^ 3) temps et O(1) mémoire pour l'approche de Lev/Inbar (si elle n'est pas implémentée de la même manière que le premier exemple de code d'Inbar).

0
Dougal

Cette post présente trois manières de trouver le sous-tableau maximum d’un tableau. 

  • Force brute (O (n * n))
  • Diviser et conquérir (O ​​(nlgn))
  • Algorithme de Kadane (O (n))

Parmi ceux-ci, le plus rapide est l'algorithme de Kadane qui a une complexité temporelle de O (n).

0
PixelsTech