-1
votes

Des carrés d'une matrice triée, pourquoi la méthode triée () est plus rapide que O (n) la méthode?

Je travaille sur l'algorithme Leetcode Problème 977. Carrés d'une matrice triée.

Pourquoi les soumissions utilisant la méthode intégrée triée sont plus rapides que ma méthode Traverselle O (n) comme ci-dessous? P>

L'entrée est une triée (non Diminution de la liste d'ordre) avec des entiers. p>

échantillon 208 MS Soumission: P>

class Solution:
    def sortedSquares(self, A: List[int]) -> List[int]:
        start = 0
        end = len(A)-1

        B = []

        while start <= end:
            if abs(A[start]) >= abs(A[end]):
                B.append(A[start] * A[start])
                start += 1
            else:
                B.append(A[end] * A[end])
                end -= 1
        B.reverse()
        return B


7 commentaires

Quelle est votre contribution?


Juste un FYI: L'algorithme décède sur l'entrée [1,3,2] déjà. "O (n) tri" est toujours méfiant.


@tevemadar Le tableau d'entrée est trié dans ce problème, mais oui, devrait certainement avoir joint la définition de problème.


Sinon: la chose est que Python n'est pas rapide. Il est rapide lorsqu'il s'agit de câblage ensemble des bibliothèques implémentées dans le code natif. Et le tri intégré est une fuselorte hautement optimisée, implémentée en C, voir github.com/pythron/cpython/blob/master/Objects/listsort.txt pour sa description élaborée, et la mise en œuvre commence à github.com/pythron/cpytthon/blob/master/Objects/... . Edit: comme @davidl. J'ai révélé que l'entrée est triée, il peut être utile d'ajouter que le tri lié est dite extrêmement bien sur des listes partiellement triées.


Merci pour vos réponses, j'aurais dû poster la description du problème plus précisions. La liste d'entrée enritique doit être la raison pour laquelle le tri () est plus rapide. Le juge en ligne aurait dû tester la situation des limites ou une longue liste, donc je ne pense pas que le CNLG (N) avec relativement petit C est le cas ici.


Ne pensez jamais trop de réflexion sur les résultats de référence de la sous-5 secondes que vous n'avez pas de raison de faire confiance à être significatif. Vous pouvez faire sans le inverse () : recherchez la limite entre les numéros négatifs et positive et procédez sur "INSID-OUT" - voir La réponse de Tevemadar pour faire sans ABS () .


Voir aussi: triés carrés de nombres dans une liste dans O (n)? .


5 Réponses :


2
votes

Juste parce que votre algorithme a un meilleur temps de fonctionnement du pire des cas ne signifie pas que ce sera mieux dans la pratique. La méthode de tri intégrée de Python est hautement optimisée, de sorte que son temps d'exécution peut être cnlg (n) pour un C relativement petit, tandis que votre algorithme, tout en étant o (n) , pourrait avoir une constante vraiment élevée d pour dn . Nous ne savons pas quelle est votre entrée, il pourrait donc s'agir d'un tableau de 10000 éléments, pour lequel d est toujours significativement plus grand que CLG (10000) .

De plus, lorsque votre liste d'entrée est triée (une partie non négative), il peut y avoir une certaine optimisation pour des listes presque triées dans ce cas (pas sûr, n'a jamais examiné la mise en œuvre de la sorte de Python).


0 commentaires

1
votes

Vous pouvez tout pré-carré (donc aucun ABS () code> est nécessaire, et surtout pas répété ABS () code> appelle pour un seul élément):

C = [x*x for x in A]

start = 0
end = len(A)-1

B = []

while start <= end:
    if C[start] >= C[end]:
        B.append(C[start])
        start += 1
    else:
        B.append(C[end])
        end -= 1
B.reverse()
return B


0 commentaires

-1
votes

Ceci est parce que Python utilise Timsort qui est une sorte d'algorithme de tri adaptatif basé sur Marge_sort et insertion_sort. et la complexité de temps est

O (nlogn)

Pour trier () en python.

C'est pourquoi trié () travaillant plus vite que vous êtes


1 commentaires

La solution de l'OP est O (n), cela n'explique donc pas pourquoi trié est plus rapide.



1
votes

Intégré de Python Trié Fonction, qui utilise Timsort , est également o (n) dans ce cas ! Vos numéros d'entrée sont triés et vous les carez. Regardons trois cas:

  • Si votre entrée ne contient que des nombres positifs, puis les squalings conservent le tri. Timsort détecte que dans O (n) temps et ne fait rien d'autre.
  • Si votre entrée ne contient que des nombres négatifs, la querelle est triée en sens inverse. Par exemple, [- 5, -4, -2, -1] devient [25, 16, 4, 1] . Timsort détecte cela et renverse simplement la liste. Temps O (n) à nouveau.
  • Si votre entrée contient des nombres négatifs et positifs, vous aurez une exécution décroissante suivie d'une course ascendante. Ensuite, Timsort détecte à la fois comme tel, inverse la course décroissante et une simple fusion des deux points. Temps O (n) à nouveau.

    Alors ... à la fois l'intégré trié et votre propre tri est O (n). Mais trié est implémenté au niveau C, ce qui est plus rapide et a accès à des raccourcis, ce qui lui donne une constante cachée plus petite.


2 commentaires

Oh, Duh, j'ai oublié de trier les listes d'entrée.


Corrigé et posté, trié est vraiment systématiquement plus rapide.



2
votes

La Time LeetCode Rapports est la somme sur tous les cas de test que votre solution a été testée. Ceci est très peu fiable comme une mesure d'efficacité algorithmique, car

  • La plupart des cas de test sont sur de petites entrées, li>
  • L'heure limitée prise par le juge lui-même est substantielle et assez variable, de sorte que même des différences modérées entre deux mesures pourraient dépendre de la variation aléatoire de cette surcharge. Li> ul>

    voir Cette réponse pour plus de discussion. p>


    donc si si Nous voulons comparer les performances des deux algorithmes, il vaut mieux le faire nous-mêmes. J'ai fait; Voici mon temps pour les listes de taille pouvant atteindre 5 000 personnes (moyenne sur 1 000 points chacune): p>

     fois 1 p>

    Voici mon temps pour les listes de listes de taille jusqu'à 1 000 000 (pas de moyenne de moyenne): p>

     fois 2 p>

    Comme vous pouvez le constater, en utilisant trié code> est toujours plus rapide Pour les petites et grandes entrées, la comparaison de Leetcode est donc correcte cette fois-ci (bien que peut-être juste par coïncidence quand même!). Votre solution est en effet linéaire et ces résultats sont compatibles avec cela. Mais la solution utilisant trié code> semble également prendre du temps linéaire, et la réponse de Wasp Overflow explique pourquoi elle devrait. P>

    Mon code de synchronisation est ci-dessous. Les temps ont été mesurés à l'aide de Python 3.5.2 et je reçois des résultats similaires avec Python 3.8.1. P>

    def linear(A):
        start = 0
        end = len(A)-1
        B = []
        while start <= end:
            if abs(A[start]) >= abs(A[end]):
                B.append(A[start] * A[start])
                start += 1
            else:
                B.append(A[end] * A[end])
                end -= 1
        B.reverse()
        return B
    
    def using_sorted(A):
        return sorted(x*x for x in A)
    
    from timeit import timeit
    from random import randint
    
    print('n', 'linear', 'using sorted', sep='\t')
    for n in range(10000, 1000001, 10000):
        data = sorted(randint(-10*n, 10*n) for i in range(n))
        t1 = timeit(lambda: linear(data), number=1)
        t2 = timeit(lambda: using_sorted(data), number=1)
        print(n, t1, t2, sep='\t')
    


2 commentaires

J'ai couru votre code et obtenu des résultats similaires, bien qu'ils ont terminé avec environ 0,95 et 0,40 seconde, la différence est donc plus forte pour moi. J'utilise 3.8.1, Leetcode utilise 3,8 , et je pense que quelque part environ 3,6 ou 3.7, ils ont amélioré de manière significative en utilisant des comparaisons plus rapides si toutes les valeurs sont des chiffres du même type.


Oui, était en 3.7: " trié () et list.sort () ont été optimisés pour Les cas communs doivent être atteints jusqu'à 40-75% plus rapidement.